[automerger skipped] Merge "libFLAC: Fix divide by zero error in FLAC__stream_decoder_seek_absolute" into mainline-prod am: ae3bb26fa7 -s ours

am skip reason: skip tag Change-Id I9165ae7fd4ddeba1d1b46203ef1256915c9f4add with SHA-1 5bd2e7aba1 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/external/flac/+/13868219

Change-Id: I049346fea39c25e0b4e44190da583c0b2d079303
diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml
new file mode 100644
index 0000000..9fd936f
--- /dev/null
+++ b/.github/workflows/action.yml
@@ -0,0 +1,153 @@
+name: GitHub Actions
+
+on: [push]
+
+jobs:
+  build:
+    strategy:
+      matrix:
+        name:
+          [
+            ubuntu-latest-gcc-autotools,
+            ubuntu-latest-clang-autotools,
+            ubuntu-latest-gcc-cmake,
+            ubuntu-latest-clang-cmake,
+            macos-latest-clang-autotools,
+            macos-latest-clang-cmake,
+            ubuntu-latest-gcc-autotools-64-bit-words,
+            ubuntu-latest-clang-autotools-64-bit-words,
+            ubuntu-latest-gcc-cmake-64-bit-words,
+            ubuntu-latest-clang-cmake-64-bit-words,
+            macos-latest-clang-autotools-64-bit-words,
+            macos-latest-clang-cmake-64-bit-words
+          ]
+        include:
+          - name: ubuntu-latest-gcc-autotools
+            os: ubuntu-latest
+            cc: gcc
+            cxx: g++
+            build-system: autotools
+            configure-opts: ''
+
+          - name: ubuntu-latest-clang-autotools
+            os: ubuntu-latest
+            cc: clang
+            cxx: clang++
+            build-system: autotools
+            configure-opts: ''
+
+          - name: ubuntu-latest-gcc-cmake
+            os: ubuntu-latest
+            cc: gcc
+            cxx: g++
+            build-system: cmake
+            configure-opts: ''
+
+          - name: ubuntu-latest-clang-cmake
+            os: ubuntu-latest
+            cc: clang
+            cxx: clang++
+            build-system: cmake
+            configure-opts: ''
+
+          - name: macos-latest-clang-autotools
+            os: macos-latest
+            cc: clang
+            cxx: clang++
+            build-system: autotools
+            configure-opts: ''
+
+          - name: macos-latest-clang-cmake
+            os: macos-latest
+            cc: clang
+            cxx: clang++
+            build-system: cmake
+            configure-opts: ''
+
+          - name: ubuntu-latest-gcc-autotools-64-bit-words
+            os: ubuntu-latest
+            cc: gcc
+            cxx: g++
+            build-system: autotools
+            configure-opts: --enable-64-bit-words
+
+          - name: ubuntu-latest-clang-autotools-64-bit-words
+            os: ubuntu-latest
+            cc: clang
+            cxx: clang++
+            build-system: autotools
+            configure-opts: --enable-64-bit-words
+
+          - name: ubuntu-latest-gcc-cmake-64-bit-words
+            os: ubuntu-latest
+            cc: gcc
+            cxx: g++
+            build-system: cmake
+            configure-opts: -DENABLE_64_BIT_WORDS=ON
+
+          - name: ubuntu-latest-clang-cmake-64-bit-words
+            os: ubuntu-latest
+            cc: clang
+            cxx: clang++
+            build-system: cmake
+            configure-opts: -DENABLE_64_BIT_WORDS=ON
+
+          - name: macos-latest-clang-autotools-64-bit-words
+            os: macos-latest
+            cc: clang
+            cxx: clang++
+            build-system: autotools
+            configure-opts: --enable-64-bit-words
+
+          - name: macos-latest-clang-cmake-64-bit-words
+            os: macos-latest
+            cc: clang
+            cxx: clang++
+            build-system: cmake
+            configure-opts: -DENABLE_64_BIT_WORDS=ON
+
+    runs-on: ${{ matrix.os }}
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Install MacOS dependencies
+        if: startsWith(matrix.os,'macos')
+        run: |
+          brew update
+          brew install automake pkg-config libogg
+
+      - name: Install Lunux dependencies
+        if: startsWith(matrix.os,'ubuntu')
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y libtool-bin libogg-dev doxygen libxml2-utils w3c-sgml-lib
+
+      - name: Build with Autotools
+        if: startsWith(matrix.build-system,'autotools')
+        env:
+          CC: ${{ matrix.cc }}
+          CXX: ${{ matrix.cxx }}
+        run: |
+          ./autogen.sh
+          ./configure ${{ matrix.configure-opts }}
+          make
+          make check
+
+      - name: Build with CMake
+        if: startsWith(matrix.build-system,'cmake')
+        env:
+          CC: ${{ matrix.cc }}
+          CXX: ${{ matrix.cxx }}
+        run: |
+          mkdir cmake-build
+          cd cmake-build
+          cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON ${{ matrix.configure-opts }} -DCMAKE_FIND_FRAMEWORK=NEVER
+          cmake --build .
+          ctest -V
+
+      - name: Check documentation
+        if: startsWith(matrix.os,'ubuntu') && startsWith(matrix.build-system,'autotools')
+        run: |
+          xmllint --valid --noout doc/html/*.html;
+          xmllint --valid --noout doc/html/api/*.html;
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8e73e13
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,96 @@
+*.a
+*.la
+*.lo
+*.o
+*.so
+*.dll
+*.dylib
+*.exe
+.deps
+.libs
+Makefile
+Makefile.in
+aclocal.m4
+ar-lib
+autom4te.cache/
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.rpath
+config.status
+config.sub
+configure
+depcomp
+doc/Doxyfile
+doc/FLAC.tag
+doc/html/api/
+examples/c/decode/file/example_c_decode_file
+examples/c/encode/file/example_c_encode_file
+examples/cpp/decode/file/example_cpp_decode_file
+examples/cpp/encode/file/example_cpp_encode_file
+install-sh
+libtool
+libtool-disable-static
+ltmain.sh
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+man/manpage.links
+man/manpage.refs
+missing
+objs/debug
+objs/release
+src/flac/flac
+src/libFLAC++/flac++.pc
+src/libFLAC/flac.pc
+src/metaflac/metaflac
+src/share/getopt/libgetopt.a
+src/test_grabbag/cuesheet/test_cuesheet
+src/test_grabbag/picture/test_picture
+src/test_libFLAC++/test_libFLAC++
+src/test_libFLAC/test_libFLAC
+src/test_seeking/test_seeking
+src/test_streams/test_streams
+stamp-h1
+test/*.aiff
+test/*.cmp
+test/*.cue
+test/*.flac
+test/*.log
+test/*.oga
+test/*.raw
+test/*.rf64
+test/*.w64
+test/*.wav
+test/common.sh
+test/cuesheet.diff
+test/cuesheet.log
+test/metaflac-test-files/out.meta
+test/metaflac.flac
+test/picture.diff
+test/picture.log
+.dirstamp
+microbench/benchmark_residual
+oss-fuzz/fuzz-decoder
+oss-fuzz/fuzz-encoder
+
+/*[Bb]uild*/
+/out/
+CMakeSettings.json
+CMakeLists.txt.user
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Testing
+Makefile
+cmake_install.cmake
+install_manifest.txt
+compile_commands.json
+CTestTestfile.cmake
+_deps
+
+/.vs*/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..784eca9
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,29 @@
+language: c
+
+os:
+  - linux
+  - osx
+
+dist: xenial
+
+compiler:
+  - gcc
+  - clang
+
+env:
+  matrix:
+  - BUILD_SYSTEM="autotools" CONFIGURE_OPTS=
+  - BUILD_SYSTEM="autotools" CONFIGURE_OPTS=--enable-64-bit-words
+  - BUILD_SYSTEM="cmake"     CONFIGURE_OPTS=
+  - BUILD_SYSTEM="cmake"     CONFIGURE_OPTS=-DENABLE_64_BIT_WORDS=ON
+install:
+  - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get -y install libtool-bin libogg-dev doxygen libxml2-utils w3c-sgml-lib; fi
+  - if [ $TRAVIS_OS_NAME = osx ]; then brew update ; brew install libogg; fi
+
+script:
+  - if [[ "${BUILD_SYSTEM}" == "autotools" ]]; then ./autogen.sh && ./configure $CONFIGURE_OPTS && make && make check; fi
+  - if [[ "${BUILD_SYSTEM}" == "cmake" ]]; then mkdir cmake-build && cd cmake-build && cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON $CONFIGURE_OPTS && cmake --build . && ctest -V; fi
+  - if [ $TRAVIS_OS_NAME = linux ] && [ ${BUILD_SYSTEM} = "autotools" ]; then
+      xmllint --valid --noout doc/html/*.html;
+      xmllint --valid --noout doc/html/api/*.html;
+    fi
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..8fe9092
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,58 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This file is part the FLAC project.  FLAC is comprised of several
+ * components distributed under different licenses.  The codec libraries
+ * are distributed under Xiph.Org's BSD-like license (see the file
+ * COPYING.Xiph in this distribution).  All other programs, libraries, and
+ * plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+ * is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+ * FLAC distribution contains at the top the terms under which it may be
+ * distributed.
+ *
+ * Since this particular file is relevant to all components of FLAC,
+ * it may be distributed under the Xiph.Org license, which is the least
+ * restrictive of those mentioned above.  See the file COPYING.Xiph in this
+ * distribution.
+ */
+
+Current FLAC maintainer: Erik de Castro Lopo <erikd@mega-nerd.com>
+
+Original author: Josh Coalson <jcoalson@users.sourceforge.net>
+
+Website : https://www.xiph.org/flac/
+
+FLAC is an Open Source lossless audio codec originally developed by Josh Coalson
+between 2001 and 2009. From 2009 to 2012 FLAC was basically unmaintained. In
+2012 the Erik de Castro Lopo became the chief maintainer as part of the
+Xiph.Org Foundation.
+
+Other major contributors and their contributions:
+
+"lvqcl" <lvqcl@users.sourceforge.net>
+* Visual Studio build system.
+* Optimisations in the encoder and decoder.
+
+"Janne Hyvärinen" <cse@sci.fi>
+* Visual Studio build system.
+* Unicode handling on Windows.
+
+"Andrey Astafiev" <andrei@tvcell.ru>
+* Russian translation of the HTML documentation
+
+"Miroslav Lichvar" <lichvarm@phoenix.inf.upol.cz>
+* IA-32 assembly versions of several libFLAC routines
+
+"Brady Patterson" <bpat@users.sourceforge.net>
+* AIFF file support, PPC assembly versions of libFLAC routines
+
+"Daisuke Shimamura" <Daisuke_Shimamura@nifty.com>
+* i18n support in the XMMS plugin
+
+"X-Fixer" <x-fixer@narod.ru>
+* Configuration system, tag editing, and file info in the Winamp2 plugin
+
+"Matt Zimmerman" <mdz@debian.org>
+* Libtool/autoconf/automake make system, flac man page
+
diff --git a/Android.bp b/Android.bp
index 3ca94c0..af7b348 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,7 +1,63 @@
+// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS.  PLEASE
+//     CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+//     DEPENDING ON IT IN YOUR PROJECT. ***
+package {
+    default_applicable_licenses: ["external_flac_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+// See: http://go/android-license-faq
+license {
+    name: "external_flac_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+        "SPDX-license-identifier-GFDL", // by exception only
+        "SPDX-license-identifier-GPL",
+        "SPDX-license-identifier-GPL-2.0",
+        "SPDX-license-identifier-LGPL",
+        "SPDX-license-identifier-LGPL-2.1",
+        "SPDX-license-identifier-LGPL-3.0",
+        "SPDX-license-identifier-MIT",
+        "legacy_unencumbered",
+    ],
+    license_text: [
+        "COPYING.FDL",
+        "COPYING.GPL",
+        "COPYING.LGPL",
+        "COPYING.Xiph",
+        "NOTICE",
+    ],
+}
+
 cc_library_headers {
     name: "libFLAC-config",
     export_include_dirs: ["."],
     vendor_available: true,
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
     min_sdk_version: "29",
 }
 
@@ -9,7 +65,13 @@
     name: "libFLAC-headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
     min_sdk_version: "29",
 }
 
-subdirs = ["libFLAC"]
+subdirs = ["src/libFLAC"]
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c83dd83
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,153 @@
+# 3.1 is OK for most parts. However:
+# 3.3 is needed in src/libFLAC
+# 3.5 is needed in src/libFLAC/ia32
+# 3.9 is needed in 'doc' because of doxygen_add_docs()
+cmake_minimum_required(VERSION 3.5)
+
+if(NOT (CMAKE_BUILD_TYPE OR CMAKE_CONFIGURATION_TYPES OR DEFINED ENV{CFLAGS} OR DEFINED ENV{CXXFLAGS}))
+    set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo")
+endif()
+
+project(FLAC VERSION 1.3.3) # HOMEPAGE_URL "https://www.xiph.org/flac/")
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+option(BUILD_CXXLIBS "Build libFLAC++" ON)
+option(BUILD_PROGRAMS "Build and install programs" ON)
+option(BUILD_EXAMPLES "Build and install examples" ON)
+option(BUILD_DOCS "Build and install doxygen documents" ON)
+option(WITH_STACK_PROTECTOR "Enable GNU GCC stack smash protection" ON)
+option(INSTALL_MANPAGES "Install MAN pages" ON)
+option(INSTALL_PKGCONFIG_MODULES "Install PkgConfig modules" ON)
+option(INSTALL_CMAKE_CONFIG_MODULE "Install CMake package-config module" ON)
+option(WITH_OGG "ogg support (default: test for libogg)" ON)
+
+if(WITH_OGG)
+    find_package(Ogg REQUIRED)
+endif()
+
+find_package(Iconv)
+set(HAVE_ICONV ${Iconv_FOUND})
+
+if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return -Wcast-align -Wnested-externs -Wshadow -Wundef -Wmissing-declarations -Winline")
+    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -funroll-loops")
+endif()
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wcast-align -Wshadow -Wwrite-strings -Wctor-dtor-privacy -Wnon-virtual-dtor -Wreorder -Wsign-promo -Wundef")
+endif()
+
+include(CMakePackageConfigHelpers)
+include(CPack)
+include(CTest)
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+include(CheckSymbolExists)
+include(CheckFunctionExists)
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(CheckCXXSourceCompiles)
+include(GNUInstallDirs)
+include(UseSystemExtensions)
+include(TestBigEndian)
+
+check_include_file("byteswap.h" HAVE_BYTESWAP_H)
+check_include_file("inttypes.h" HAVE_INTTYPES_H)
+check_include_file("stdint.h" HAVE_STDINT_H)
+if(MSVC)
+    check_include_file("intrin.h" FLAC__HAS_X86INTRIN)
+else()
+    check_include_file("x86intrin.h" FLAC__HAS_X86INTRIN)
+endif()
+
+check_function_exists(fseeko HAVE_FSEEKO)
+
+check_c_source_compiles("int main() { return __builtin_bswap16 (0) ; }" HAVE_BSWAP16)
+check_c_source_compiles("int main() { return __builtin_bswap32 (0) ; }" HAVE_BSWAP32)
+
+test_big_endian(CPU_IS_BIG_ENDIAN)
+
+check_c_compiler_flag(-Werror HAVE_WERROR_FLAG)
+check_c_compiler_flag(-Wdeclaration-after-statement HAVE_DECL_AFTER_STMT_FLAG)
+check_c_compiler_flag(-mstackrealign HAVE_STACKREALIGN_FLAG)
+check_cxx_compiler_flag(-Weffc++ HAVE_WEFFCXX_FLAG)
+
+if(WITH_STACK_PROTECTOR)
+  if(NOT MSVC)
+    check_c_compiler_flag("-fstack-protector-strong" HAVE_STACK_PROTECTOR_FLAG)
+  endif()
+endif()
+
+if(HAVE_WERROR_FLAG)
+    option(ENABLE_WERROR "Enable -Werror in all Makefiles" OFF)
+endif()
+
+add_compile_options(
+    $<$<BOOL:${MSVC}>:/wd4267>
+    $<$<BOOL:${MSVC}>:/wd4996>
+    $<$<BOOL:${ENABLE_WERROR}>:-Werror>
+    $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:${HAVE_WEFFCXX_FLAG}>>:-Weffc++>
+    $<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:${HAVE_DECL_AFTER_STMT_FLAG}>>:-Wdeclaration-after-statement>)
+
+if(HAVE_STACK_PROTECTOR_FLAG)
+    add_compile_options(-fstack-protector-strong)
+endif()
+
+if(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" AND HAVE_STACKREALIGN_FLAG)
+    add_compile_options(-mstackrealign)
+endif()
+
+include_directories("include")
+
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+add_definitions(-DHAVE_CONFIG_H)
+
+if(MSVC)
+    add_definitions(
+        -D_CRT_SECURE_NO_WARNINGS
+        -D_USE_MATH_DEFINES)
+endif()
+if(CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo)
+    add_definitions(-DFLAC__OVERFLOW_DETECT)
+endif()
+
+add_subdirectory("src")
+add_subdirectory("microbench")
+if(BUILD_DOCS)
+    add_subdirectory("doc")
+endif()
+if(BUILD_EXAMPLES)
+    add_subdirectory("examples")
+endif()
+if(BUILD_TESTING)
+    add_subdirectory("test")
+endif()
+
+configure_file(config.cmake.h.in config.h)
+
+if(INSTALL_CMAKE_CONFIG_MODULE)
+    install(
+        EXPORT targets
+        DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake"
+        NAMESPACE FLAC::)
+
+    configure_package_config_file(
+        flac-config.cmake.in flac-config.cmake
+        INSTALL_DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake")
+    write_basic_package_version_file(
+        flac-config-version.cmake COMPATIBILITY AnyNewerVersion)
+
+    install(
+        FILES
+            "${CMAKE_CURRENT_BINARY_DIR}/flac-config.cmake"
+            "${CMAKE_CURRENT_BINARY_DIR}/flac-config-version.cmake"
+        DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake")
+endif()
+
+file(GLOB FLAC_HEADERS "include/FLAC/*.h")
+file(GLOB FLAC++_HEADERS "include/FLAC++/*.h")
+install(FILES ${FLAC_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/FLAC")
+install(FILES ${FLAC++_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/FLAC++")
+if(INSTALL_MANPAGES)
+    install(FILES "man/flac.1" "man/metaflac.1" DESTINATION "${CMAKE_INSTALL_MANDIR}")
+endif()
diff --git a/COPYING.FDL b/COPYING.FDL
new file mode 100644
index 0000000..4a0fe1c
--- /dev/null
+++ b/COPYING.FDL
@@ -0,0 +1,397 @@
+		GNU Free Documentation License
+		  Version 1.2, November 2002
+
+
+ Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The "Document", below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as "you".  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject.  (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification.  Examples of
+transparent image formats include PNG, XCF and JPG.  Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has fewer than five),
+   unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+   to it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section Entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+   Preserve the Title of the section, and preserve in the section all
+   the substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+   or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications".  You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License.  Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License.  However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+    Copyright (c)  YEAR  YOUR NAME.
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.2
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+    with the Invariant Sections being LIST THEIR TITLES, with the
+    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/COPYING.GPL b/COPYING.GPL
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/COPYING.GPL
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/COPYING.LGPL b/COPYING.LGPL
new file mode 100644
index 0000000..5ab7695
--- /dev/null
+++ b/COPYING.LGPL
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/COPYING.Xiph b/COPYING.Xiph
new file mode 100644
index 0000000..d8295f0
--- /dev/null
+++ b/COPYING.Xiph
@@ -0,0 +1,29 @@
+Copyright (C) 2000-2009  Josh Coalson
+Copyright (C) 2011-2016  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.
diff --git a/FLAC-vs2005.sln b/FLAC-vs2005.sln
new file mode 100644
index 0000000..c35b07c
--- /dev/null
+++ b/FLAC-vs2005.sln
@@ -0,0 +1,249 @@
+

+Microsoft Visual Studio Solution File, Format Version 9.00

+# Visual C++ Express 2005

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_c_decode_file", "examples\c\decode\file\example_c_decode_file.vcproj", "{4CEFBD00-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_c_encode_file", "examples\c\encode\file\example_c_encode_file.vcproj", "{4CEFBD01-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_cpp_decode_file", "examples\cpp\decode\file\example_cpp_decode_file.vcproj", "{4CEFBE00-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBC86-C215-11DB-8314-0800200C9A66} = {4CEFBC86-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_cpp_encode_file", "examples\cpp\encode\file\example_cpp_encode_file.vcproj", "{4CEFBE01-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBC86-C215-11DB-8314-0800200C9A66} = {4CEFBC86-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flac", "src\flac\flac.vcproj", "{4CEFBC7D-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC81-C215-11DB-8314-0800200C9A66} = {4CEFBC81-C215-11DB-8314-0800200C9A66}

+		{4CEFBC89-C215-11DB-8314-0800200C9A66} = {4CEFBC89-C215-11DB-8314-0800200C9A66}

+		{4CEFBC92-C215-11DB-8314-0800200C9A66} = {4CEFBC92-C215-11DB-8314-0800200C9A66}

+		{4CEFBC80-C215-11DB-8314-0800200C9A66} = {4CEFBC80-C215-11DB-8314-0800200C9A66}

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66} = {4CEFBC8A-C215-11DB-8314-0800200C9A66}

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBE02-C215-11DB-8314-0800200C9A66} = {4CEFBE02-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iffscan", "src\flac\iffscan.vcproj", "{4CEFBC94-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBE02-C215-11DB-8314-0800200C9A66} = {4CEFBE02-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flacdiff", "src\utils\flacdiff\flacdiff.vcproj", "{4CEFBC93-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBC86-C215-11DB-8314-0800200C9A66} = {4CEFBC86-C215-11DB-8314-0800200C9A66}

+		{4CEFBE02-C215-11DB-8314-0800200C9A66} = {4CEFBE02-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flactimer", "src\utils\flactimer\flactimer.vcproj", "{4CEFBC95-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt_static", "src\share\getopt\getopt_static.vcproj", "{4CEFBC80-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grabbag_static", "src\share\grabbag\grabbag_static.vcproj", "{4CEFBC81-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBC89-C215-11DB-8314-0800200C9A66} = {4CEFBC89-C215-11DB-8314-0800200C9A66}

+		{4CEFBE02-C215-11DB-8314-0800200C9A66} = {4CEFBE02-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC_dynamic", "src\libFLAC\libFLAC_dynamic.vcproj", "{4CEFBC83-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC_static", "src\libFLAC\libFLAC_static.vcproj", "{4CEFBC84-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC++_dynamic", "src\libFLAC++\libFLAC++_dynamic.vcproj", "{4CEFBC85-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC83-C215-11DB-8314-0800200C9A66} = {4CEFBC83-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC++_static", "src\libFLAC++\libFLAC++_static.vcproj", "{4CEFBC86-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "metaflac", "src\metaflac\metaflac.vcproj", "{4CEFBC87-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBC80-C215-11DB-8314-0800200C9A66} = {4CEFBC80-C215-11DB-8314-0800200C9A66}

+		{4CEFBC92-C215-11DB-8314-0800200C9A66} = {4CEFBC92-C215-11DB-8314-0800200C9A66}

+		{4CEFBC89-C215-11DB-8314-0800200C9A66} = {4CEFBC89-C215-11DB-8314-0800200C9A66}

+		{4CEFBC81-C215-11DB-8314-0800200C9A66} = {4CEFBC81-C215-11DB-8314-0800200C9A66}

+		{4CEFBE02-C215-11DB-8314-0800200C9A66} = {4CEFBE02-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "replaygain_analysis_static", "src\share\replaygain_analysis\replaygain_analysis_static.vcproj", "{4CEFBC89-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "replaygain_synthesis_static", "src\share\replaygain_synthesis\replaygain_synthesis_static.vcproj", "{4CEFBC8A-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cuesheet", "src\test_grabbag\cuesheet\test_cuesheet.vcproj", "{4CEFBC8B-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBC81-C215-11DB-8314-0800200C9A66} = {4CEFBC81-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libFLAC", "src\test_libFLAC\test_libFLAC.vcproj", "{4CEFBC8C-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66} = {4CEFBC8E-C215-11DB-8314-0800200C9A66}

+		{4CEFBC81-C215-11DB-8314-0800200C9A66} = {4CEFBC81-C215-11DB-8314-0800200C9A66}

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libFLAC++", "src\test_libFLAC++\test_libFLAC++.vcproj", "{4CEFBC8D-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBC86-C215-11DB-8314-0800200C9A66} = {4CEFBC86-C215-11DB-8314-0800200C9A66}

+		{4CEFBC81-C215-11DB-8314-0800200C9A66} = {4CEFBC81-C215-11DB-8314-0800200C9A66}

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66} = {4CEFBC8E-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libs_common_static", "src\test_libs_common\test_libs_common_static.vcproj", "{4CEFBC8E-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_picture", "src\test_grabbag\picture\test_picture.vcproj", "{4CEFBC8F-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+		{4CEFBC81-C215-11DB-8314-0800200C9A66} = {4CEFBC81-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_seeking", "src\test_seeking\test_seeking.vcproj", "{4CEFBC90-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC84-C215-11DB-8314-0800200C9A66} = {4CEFBC84-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_streams", "src\test_streams\test_streams.vcproj", "{4CEFBC91-C215-11DB-8314-0800200C9A66}"

+	ProjectSection(ProjectDependencies) = postProject

+		{4CEFBC81-C215-11DB-8314-0800200C9A66} = {4CEFBC81-C215-11DB-8314-0800200C9A66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "utf8_static", "src\share\utf8\utf8_static.vcproj", "{4CEFBC92-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_utf8_io_static", "src\share\win_utf8_io\win_utf8_io_static.vcproj", "{4CEFBE02-C215-11DB-8314-0800200C9A66}"

+EndProject

+Global

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Debug|Win32 = Debug|Win32

+		Release|Win32 = Release|Win32

+	EndGlobalSection

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+	EndGlobalSection

+	GlobalSection(SolutionProperties) = preSolution

+		HideSolutionNode = FALSE

+	EndGlobalSection

+EndGlobal

diff --git a/FLAC.sln b/FLAC.sln
new file mode 100644
index 0000000..1c175f8
--- /dev/null
+++ b/FLAC.sln
@@ -0,0 +1,278 @@
+

+Microsoft Visual Studio Solution File, Format Version 12.00

+# Visual Studio Express 2013 for Windows Desktop

+VisualStudioVersion = 12.0.30501.0

+MinimumVisualStudioVersion = 10.0.40219.1

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_c_decode_file", "examples\c\decode\file\example_c_decode_file.vcxproj", "{4CEFBD00-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_c_encode_file", "examples\c\encode\file\example_c_encode_file.vcxproj", "{4CEFBD01-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_cpp_decode_file", "examples\cpp\decode\file\example_cpp_decode_file.vcxproj", "{4CEFBE00-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_cpp_encode_file", "examples\cpp\encode\file\example_cpp_encode_file.vcxproj", "{4CEFBE01-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flac", "src\flac\flac.vcxproj", "{4CEFBC7D-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iffscan", "src\flac\iffscan.vcxproj", "{4CEFBC94-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flacdiff", "src\utils\flacdiff\flacdiff.vcxproj", "{4CEFBC93-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flactimer", "src\utils\flactimer\flactimer.vcxproj", "{4CEFBC95-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt_static", "src\share\getopt\getopt_static.vcxproj", "{4CEFBC80-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grabbag_static", "src\share\grabbag\grabbag_static.vcxproj", "{4CEFBC81-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC_dynamic", "src\libFLAC\libFLAC_dynamic.vcxproj", "{4CEFBC83-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC_static", "src\libFLAC\libFLAC_static.vcxproj", "{4CEFBC84-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC++_dynamic", "src\libFLAC++\libFLAC++_dynamic.vcxproj", "{4CEFBC85-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC++_static", "src\libFLAC++\libFLAC++_static.vcxproj", "{4CEFBC86-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "metaflac", "src\metaflac\metaflac.vcxproj", "{4CEFBC87-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "replaygain_analysis_static", "src\share\replaygain_analysis\replaygain_analysis_static.vcxproj", "{4CEFBC89-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "replaygain_synthesis_static", "src\share\replaygain_synthesis\replaygain_synthesis_static.vcxproj", "{4CEFBC8A-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cuesheet", "src\test_grabbag\cuesheet\test_cuesheet.vcxproj", "{4CEFBC8B-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libFLAC", "src\test_libFLAC\test_libFLAC.vcxproj", "{4CEFBC8C-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libFLAC++", "src\test_libFLAC++\test_libFLAC++.vcxproj", "{4CEFBC8D-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libs_common_static", "src\test_libs_common\test_libs_common_static.vcxproj", "{4CEFBC8E-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_picture", "src\test_grabbag\picture\test_picture.vcxproj", "{4CEFBC8F-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_seeking", "src\test_seeking\test_seeking.vcxproj", "{4CEFBC90-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_streams", "src\test_streams\test_streams.vcxproj", "{4CEFBC91-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "utf8_static", "src\share\utf8\utf8_static.vcxproj", "{4CEFBC92-C215-11DB-8314-0800200C9A66}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_utf8_io_static", "src\share\win_utf8_io\win_utf8_io_static.vcxproj", "{4CEFBE02-C215-11DB-8314-0800200C9A66}"

+EndProject

+Global

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Debug|Win32 = Debug|Win32

+		Debug|x64 = Debug|x64

+		Release|Win32 = Release|Win32

+		Release|x64 = Release|x64

+	EndGlobalSection

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBD00-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBD01-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBE00-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBE01-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC7D-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC94-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC93-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC95-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC80-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC81-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC83-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC84-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC85-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC86-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC87-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC89-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC8A-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC8B-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC8C-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC8D-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC8E-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC8F-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC90-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC91-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBC92-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Debug|x64.Build.0 = Debug|x64

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Release|Win32.Build.0 = Release|Win32

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Release|x64.ActiveCfg = Release|x64

+		{4CEFBE02-C215-11DB-8314-0800200C9A66}.Release|x64.Build.0 = Release|x64

+	EndGlobalSection

+	GlobalSection(SolutionProperties) = preSolution

+		HideSolutionNode = FALSE

+	EndGlobalSection

+EndGlobal

diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..b760b2b
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,22 @@
+# *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS.  PLEASE
+#     CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+#     DEPENDING ON IT IN YOUR PROJECT. ***
+name: "flac"
+description: "Android fork of the flac library."
+third_party {
+  url {
+    type: GIT
+    value: "https://github.com/xiph/flac.git"
+  }
+  version: "bfd4f13f3eb1f4d4f9f723e343f63eceedb267ba"
+  # Would be RESTRICTED save for GFDL in:
+  #   README
+  #   COPYING.FDL
+  #   doc/html/flac.css
+  license_type: BY_EXCEPTION_ONLY
+  last_upgrade_date {
+    year: 2020
+    month: 12
+    day: 17
+  }
+}
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..7729c36
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,62 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# automake provides the following useful targets:
+#
+# all: build all programs and libraries using the current
+# configuration (set by configure)
+#
+# check: build and run all self-tests
+#
+# clean: remove everything except what's required to build everything
+#
+# distclean: remove everything except what goes in the distribution
+#
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = doc include m4 man src test build microbench oss-fuzz
+
+if EXAMPLES
+SUBDIRS += examples
+endif
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	config.cmake.h.in \
+	flac-config.cmake.in \
+	cmake/FindOgg.cmake \
+	cmake/UseSystemExtensions.cmake \
+	cmake/CheckCPUArch.cmake \
+	cmake/CheckCPUArch.c.in \
+	COPYING.FDL \
+	COPYING.GPL \
+	COPYING.LGPL \
+	COPYING.Xiph \
+	FLAC.sln \
+	FLAC-vs2005.sln \
+	Makefile.lite \
+	Makefile.deps \
+	autogen.sh \
+	config.rpath \
+	depcomp \
+	ltmain.sh \
+	strip_non_asm_libtool_args.sh
+
+CLEANFILES = *~
diff --git a/Makefile.deps b/Makefile.deps
new file mode 100644
index 0000000..a7a5ed7
--- /dev/null
+++ b/Makefile.deps
@@ -0,0 +1,39 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+ifeq ($(findstring Windows,$(OS)),Windows) # "Windows" is provided by GNU Make's internal $(OS)
+    WIN_DEPS = share/win_utf8_io
+else
+    WIN_DEPS =
+endif
+
+flac: libFLAC share $(WIN_DEPS)
+libFLAC++: libFLAC
+metaflac: libFLAC share $(WIN_DEPS)
+plugin_common: libFLAC
+plugin_xmms: libFLAC plugin_common
+share: libFLAC
+test_grabbag: share
+test_libs_common: libFLAC
+test_libFLAC++: libFLAC libFLAC++ test_libs_common
+test_libFLAC: libFLAC test_libs_common
+test_seeking: libFLAC
+test_streams: share
+flacdiff: libFLAC libFLAC++ $(WIN_DEPS)
+flactimer:
+utils: flacdiff flactimer
diff --git a/Makefile.lite b/Makefile.lite
new file mode 100644
index 0000000..2b394af
--- /dev/null
+++ b/Makefile.lite
@@ -0,0 +1,77 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU Makefile
+#
+# Useful targets
+#
+# all     : build all libraries and programs in the default configuration (currently 'release')
+# debug   : build all libraries and programs in debug mode
+# valgrind: build all libraries and programs in debug mode, dynamically linked and ready for valgrind
+# release : build all libraries and programs in release mode
+# test    : run the unit and stream tests
+# clean   : remove all non-distro files
+#
+
+topdir = .
+
+.PHONY: all doc src examples libFLAC libFLAC++ share plugin_common flac metaflac test_grabbag test_libFLAC test_libFLAC++ test_seeking test_streams flacdiff flactimer
+all: src examples
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+doc:
+	(cd $@ && $(MAKE) -f Makefile.lite)
+
+src examples:
+	(cd $@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+libFLAC libFLAC++ share flac metaflac plugin_common plugin_xmms test_libs_common test_seeking test_streams test_grabbag test_libFLAC test_libFLAC++:
+	(cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+flacdiff flactimer:
+	(cd src/utils/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+test: debug
+	(cd test && $(MAKE) -f Makefile.lite debug)
+
+testv: valgrind
+	(cd test && $(MAKE) -f Makefile.lite valgrind)
+
+testr: release
+	(cd test && $(MAKE) -f Makefile.lite release)
+
+clean:
+	-(cd doc && $(MAKE) -f Makefile.lite clean)
+	-(cd src && $(MAKE) -f Makefile.lite clean)
+	-(cd examples && $(MAKE) -f Makefile.lite clean)
+	-(cd test && $(MAKE) -f Makefile.lite clean)
+
+examples: libFLAC libFLAC++ share
+include $(topdir)/Makefile.deps
diff --git a/OWNERS b/OWNERS
index 013abf5..6d4fdcd 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,6 @@
 # Default code reviewers picked from top 3 or more developers.
 # Please update this list if you find better candidates.
+include platform/frameworks/av:/media/janitors/codec_OWNERS
 hunga@google.com
 ivanlozano@google.com
 robertshih@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..ecf8b8e
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,2 @@
+[Hook Scripts]
+mainline_hook = ${REPO_ROOT}/frameworks/av/tools/mainline_hook_project.sh
diff --git a/README b/README
new file mode 100644
index 0000000..ed2de3b
--- /dev/null
+++ b/README
@@ -0,0 +1,336 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This file is part the FLAC project.  FLAC is comprised of several
+ * components distributed under different licenses.  The codec libraries
+ * are distributed under Xiph.Org's BSD-like license (see the file
+ * COPYING.Xiph in this distribution).  All other programs, libraries, and
+ * plugins are distributed under the LGPL or GPL (see COPYING.LGPL and
+ * COPYING.GPL).  The documentation is distributed under the Gnu FDL (see
+ * COPYING.FDL).  Each file in the FLAC distribution contains at the top the
+ * terms under which it may be distributed.
+ *
+ * Since this particular file is relevant to all components of FLAC,
+ * it may be distributed under the Xiph.Org license, which is the least
+ * restrictive of those mentioned above.  See the file COPYING.Xiph in this
+ * distribution.
+ */
+
+
+FLAC is an Open Source lossless audio codec developed by Josh Coalson from 2001
+to 2009.
+
+From January 2012 FLAC is being maintained by Erik de Castro Lopo under the
+auspices of the Xiph.org Foundation.
+
+FLAC is comprised of
+  * `libFLAC', a library which implements reference encoders and
+    decoders for native FLAC and Ogg FLAC, and a metadata interface
+  * `libFLAC++', a C++ object wrapper library around libFLAC
+  * `flac', a command-line program for encoding and decoding files
+  * `metaflac', a command-line program for viewing and editing FLAC
+    metadata
+  * player plugin for XMMS
+  * user and API documentation
+
+The libraries (libFLAC, libFLAC++) are
+licensed under Xiph.org's BSD-like license (see COPYING.Xiph).  All other
+programs and plugins are licensed under the GNU General Public License
+(see COPYING.GPL).  The documentation is licensed under the GNU Free
+Documentation License (see COPYING.FDL).
+
+
+===============================================================================
+FLAC - 1.3.3 - Contents
+===============================================================================
+
+- Introduction
+- Prerequisites
+- Note to embedded developers
+- Building in a GNU environment
+- Building with Makefile.lite
+- Building with MSVC
+- Building on Mac OS X
+- Building with CMake
+
+
+===============================================================================
+Introduction
+===============================================================================
+
+This is the source release for the FLAC project.  See
+
+	doc/html/index.html
+
+for full documentation.
+
+A brief description of the directory tree:
+
+	doc/          the HTML documentation
+	examples/     example programs demonstrating the use of libFLAC and libFLAC++
+	include/      public include files for libFLAC and libFLAC++
+	man/          the man pages for `flac' and `metaflac'
+	src/          the source code and private headers
+	test/         the test scripts
+
+If you have questions about building FLAC that this document does not answer,
+please submit them at the following tracker so this document can be improved:
+
+	https://sourceforge.net/p/flac/support-requests/
+
+
+===============================================================================
+Prerequisites
+===============================================================================
+
+To build FLAC with support for Ogg FLAC you must have built and installed
+libogg according to the specific instructions below.  You must have
+libogg 1.1.2 or greater, or there will be seeking problems with Ogg FLAC.
+
+If you are building on x86 and want the assembly optimizations, you will
+need to have NASM >= 0.98.30 installed according to the specific instructions
+below.
+
+
+===============================================================================
+Note to embedded developers
+===============================================================================
+
+libFLAC has grown larger over time as more functionality has been
+included, but much of it may be unnecessary for a particular embedded
+implementation.  Unused parts may be pruned by some simple editing of
+configure.ac and src/libFLAC/Makefile.am; the following dependency
+graph shows which modules may be pruned without breaking things
+further down:
+
+metadata.h
+	stream_decoder.h
+	format.h
+
+stream_encoder.h
+	stream_decoder.h
+	format.h
+
+stream_decoder.h
+	format.h
+
+In other words, for pure decoding applications, both the stream encoder
+and metadata editing interfaces can be safely removed.
+
+There is a section dedicated to embedded use in the libFLAC API
+HTML documentation (see doc/html/api/index.html).
+
+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.
+
+
+===============================================================================
+Building in a GNU environment
+===============================================================================
+
+FLAC uses autoconf and libtool for configuring and building.
+Better documentation for these will be forthcoming, but in
+general, this should work:
+
+./configure && make && make check && make install
+
+The 'make check' step is optional; omit it to skip all the tests,
+which can take several hours and use around 70-80 megs of disk space.
+Even though it will stop with an explicit message on any failure, it
+does print out a lot of stuff so you might want to capture the output
+to a file if you're having a problem.  Also, don't run 'make check'
+as root because it confuses some of the tests.
+
+NOTE: Despite our best efforts it's entirely possible to have
+problems when using older versions of autoconf, automake, or
+libtool.  If you have the latest versions and still can't get it
+to work, see the next section on Makefile.lite.
+
+There are a few FLAC-specific arguments you can give to
+`configure':
+
+--enable-debug : Builds everything with debug symbols and some
+extra (and more verbose) error checking.
+
+--disable-asm-optimizations : Disables the compilation of the
+assembly routines.  Many routines have assembly versions for
+speed and `configure' is pretty good about knowing what is
+supported, but you can use this option to build only from the
+C sources.  May be necessary for building on OS X (Intel).
+
+--enable-sse : If you are building for an x86 CPU that supports
+SSE instructions, you can enable some of the faster routines
+if your operating system also supports SSE instructions.  flac
+can tell if the CPU supports the instructions but currently has
+no way to test if the OS does, so if it does, you must pass
+this argument to configure to use the SSE routines.  If flac
+crashes when built with this option you will have to go back and
+configure without --enable-sse.  Note that
+--disable-asm-optimizations implies --disable-sse.
+
+--enable-local-xmms-plugin : Installs the FLAC XMMS plugin in
+$HOME/.xmms/Plugins, instead of the global XMMS plugin area
+(usually /usr/lib/xmms/Input).
+
+--with-ogg=
+--with-xmms-prefix=
+--with-libiconv-prefix=
+Use these if you have these packages but configure can't find them.
+
+If you want to build completely from scratch (i.e. starting with just
+configure.ac and Makefile.am) you should be able to just run 'autogen.sh'
+but make sure and read the comments in that file first.
+
+
+===============================================================================
+Building with Makefile.lite
+===============================================================================
+
+There is a more lightweight build system for do-it-yourself-ers.
+It is also useful if configure isn't working, which may be the
+case since lately we've had some problems with different versions
+of automake and libtool.  The Makefile.lite system should work
+on GNU systems with few or no adjustments.
+
+From the top level just 'make -f Makefile.lite'.  You can
+specify zero or one optional target from 'release', 'debug',
+'test', or 'clean'.  The default is 'release'.  There is no
+'install' target but everything you need will end up in the
+obj/ directory.
+
+If you are not on an x86 system or you don't have nasm, you
+may have to change the DEFINES in src/libFLAC/Makefile.lite.  If
+you don't have nasm, remove -DFLAC__HAS_NASM.  If your target is
+not an x86, change -DFLAC__CPU_IA32 to -DFLAC__CPU_UNKNOWN.
+
+
+===============================================================================
+Building with MSVC
+===============================================================================
+
+There are .vcproj projects and a master FLAC.sln solution to build all
+the libraries and executables with MSVC 2005 or newer.
+
+Prerequisite: you must have the Ogg libraries installed as described
+later.
+
+Prerequisite: you must have nasm installed, and nasm.exe must be in
+your PATH, or the path to nasm.exe must be added to the list of
+directories for executable files in the MSVC global options.
+
+To build everything, run Visual Studio, do File|Open and open FLAC.sln.
+From the dropdown in the toolbar, select "Release" instead of "Debug",
+then do Build|Build Solution.
+
+This will build all libraries both statically (e.g.
+objs\release\lib\libFLAC_static.lib) and as DLLs (e.g.
+objs\release\lib\libFLAC.dll), and it will build all binaries, statically
+linked (e.g. objs\release\bin\flac.exe).
+
+Everything will end up in the "objs" directory.  DLLs and .exe files
+are all that are needed and can be copied to an installation area and
+added to the PATH.
+
+By default the code is configured with Ogg support. Before building FLAC
+you will need to get the Ogg source distribution
+(see http://xiph.org/downloads/), build libogg_static.lib (load
+win32\libogg_static.sln, change solution configuration to "Release" and
+code generation to "Multi-threaded (/MT)", then build), copy libogg_static.lib
+into FLAC's 'objs\release\lib' directory, and copy the entire include\ogg tree
+into FLAC's 'include' directory (so that there is an 'ogg' directory in FLAC's
+'include' directory with the files ogg.h, os_types.h and config_types.h).
+
+If you want to build without Ogg support, instead edit all .vcproj files
+and remove any "FLAC__HAS_OGG" definitions.
+
+
+===============================================================================
+Building on Mac OS X
+===============================================================================
+
+If you have Fink or a recent version of OS X with the proper autotools,
+the GNU flow above should work.
+
+
+===============================================================================
+Building with CMake
+===============================================================================
+
+CMake is a cross-platform build system. FLAC can be built on Windows, Linux, Mac
+OS X using CMake.
+
+You can use either CMake's CLI or GUI. We recommend you to have a separate build
+folder outside the repository in order to not spoil it with generated files.
+
+CLI
+---
+   Go to your build folder and run something like this:
+
+   /path/to/flac/build$ cmake /path/to/flac/source
+
+   or e.g. in Windows shell
+
+   C:\path\to\flac\build> cmake \path\to\flac\source
+   (provided that cmake is in your %PATH% variable)
+
+   That will generate build scripts for the default build system (e.g. Makefiles
+   for UNIX). After that you start build with a command like this:
+
+   /path/to/flac/build$ make
+
+   And afterwards you can run tests or install the built libraries and headers
+
+   /path/to/flac/build$ make test
+   /path/to/flac/build$ make install
+
+   If you want use a build system other than default add -G flag to cmake, e.g.:
+
+   /path/to/flac/build$ cmake /path/to/flac/source -GNinja
+   /path/to/flac/build$ ninja
+
+   or:
+
+   /path/to/flac/build$ cmake /path/to/flac/source -GXcode
+
+   Use cmake --help to see the list of available generators.
+
+   If you have OGG on your system you can tell CMake to use it:
+
+   /path/to/flac/build$ cmake /path/to/flac/source -DWITH_OGG=ON
+
+   If CMake fails to find it you can help CMake by specifying the exact path:
+
+   /path/to/flac/build$ cmake /path/to/flac/source -DWITH_OGG=ON -DOGG_ROOT=/path/to/ogg
+
+   CMake will search for OGG by default so if you don't have it you can tell
+   cmake to not do so:
+
+   /path/to/flac/build$ cmake /path/to/flac/source -DWITH_OGG=OFF
+
+   Other FLAC's options (e.g. building C++ lib or docs) can also be put to cmake
+   through -D flag.
+
+GUI
+---
+   It is likely that you would prefer to use it on Windows building for Visual
+   Studio.  It's in essence the same process as building using CLI.
+
+   Open cmake-gui. In the window select a source directory (the repository's
+   root), a build directory (some other directory outside the repository). Then
+   press button "Configure". CMake will ask you which build system you prefer.
+   Choose that version of Visual Studio which you have on your system, choose
+   whether you want to build for x86 or amd64. Press OK. After CMake finishes
+   press "Generate" button, and after that "Open Project". In response CMake
+   will launch Visual Studio and open the generated solution. You can use it as
+   usual but remember that it was generated by CMake. That means that your
+   changes (e.g. some addidional compile flags) will be lost when you run CMake
+   next time.
+
+   Again, if you have OGG on your system set WITH_OGG flag in the list of
+   variables in cmake-gui window before you press "Configure".
+
+   If CMake fails to find MSVC compiler then running cmake-gui from MS Developer
+   comand prompt should help.
diff --git a/README.version b/README.version
index 7f4074e..453501a 100644
--- a/README.version
+++ b/README.version
@@ -1,3 +1,7 @@
-URL: https://ftp.osuosl.org/pub/xiph/releases/flac/flac-1.3.2.tar.xz
-Version: 1.3.2
-BugComponent: 42195
+This commit is upto-date with following the commit in upstream-master
+Branch: upstream-master
+commit: ce6dd6b5732e319ef60716d9cc9af6a836a4011a
+
+upstream-master is in sync with upstream project at
+URL: https://github.com/xiph/flac.git
+
diff --git a/Scripts/cross-build-win-binaries.mk b/Scripts/cross-build-win-binaries.mk
new file mode 100755
index 0000000..9659655
--- /dev/null
+++ b/Scripts/cross-build-win-binaries.mk
@@ -0,0 +1,121 @@
+#!/usr/bin/make -f
+
+#  Copyright (C) 2014-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+ogg_version = 1.3.2
+ogg_sha256sum = e19ee34711d7af328cb26287f4137e70630e7261b17cbe3cd41011d73a654692
+
+flac_version = $(shell grep ^AC_INIT configure.ac | sed 's/[^ ]* \[//;s/\].*//')
+
+win_build = $(shell pwd)/win-build
+
+win32_name = i686-w64-mingw32
+win64_name = x86_64-w64-mingw32
+
+win32_target = --host=$(win32_name) --target=$(win32_name)
+win64_target = --host=$(win64_name) --target=$(win64_name)
+
+flac-$(flac_version)-win.zip : flac-$(flac_version)-win//AUTHORS
+	zip -r $@ flac-$(flac_version)-win
+	rm -rf flac-$(flac_version)-win
+
+
+
+flac-$(flac_version)-win//AUTHORS : win-build/.stamp-flac-win32-install win-build/.stamp-flac-win64-install
+	mkdir -p flac-$(flac_version)-win/win32  flac-$(flac_version)-win/win64
+	cp $(win_build)/flac32/bin/flac.exe flac-$(flac_version)-win/win32/
+	cp $(win_build)/flac32/bin/metaflac.exe flac-$(flac_version)-win/win32/
+	$(win32_name)-strip flac-$(flac_version)-win/win32/*.exe
+	cp $(win_build)/flac64/bin/flac.exe flac-$(flac_version)-win/win64/
+	cp $(win_build)/flac64/bin/metaflac.exe flac-$(flac_version)-win/win64/
+	$(win64_name)-strip flac-$(flac_version)-win/win64/*.exe
+	cp -r doc/html flac-$(flac_version)-win/
+	rm -rf flac-$(flac_version)-win/html/api
+	find flac-$(flac_version)-win/ -name Makefile\* -exec rm -f {} \;
+	cp AUTHORS COPYING.* README flac-$(flac_version)-win/
+	touch $@
+
+#-------------------------------------------------------------------------------
+# Build and install 32 and 64 bit versions of a statically linked flac and
+# metaflac executable.
+
+win-build/.stamp-flac-win64-install : win-build/.stamp-flac-win64-config
+	make clean all install
+	touch $@
+
+win-build/.stamp-flac-win64-config : win-build/.stamp-flac-prepare configure
+	mkdir -p $(win_build)/ogg64
+	./configure --disable-shared  $(win64_target) --with-ogg=$(win_build)/ogg64 --prefix=$(win_build)/flac64
+	touch $@
+
+win-build/.stamp-flac-win32-install : win-build/.stamp-flac-win32-config
+	make clean all install
+	touch $@
+
+win-build/.stamp-flac-win32-config : win-build/.stamp-flac-prepare configure
+	mkdir -p $(win_build)/ogg32
+	./configure --disable-shared  $(win32_target) --with-ogg=$(win_build)/ogg32 --prefix=$(win_build)/flac32
+	touch $@
+
+win-build/.stamp-flac-prepare : win-build/.stamp-win32-install win-build/.stamp-win64-install
+	touch $@
+
+#-------------------------------------------------------------------------------
+# Build libogg for win32 and win64.
+
+win-build/.stamp-win64-install : win-build/.stamp-win64-configure
+	(cd win-build/libogg-$(ogg_version) && make clean all check install)
+	touch $@
+
+win-build/.stamp-win64-configure : win-build/.stamp-source
+	mkdir -p $(win_build)/win64
+	(cd win-build/libogg-$(ogg_version) && ./configure --prefix=$(win_build)/ogg64 $(win32_target) --disable-shared)
+	touch $@
+
+win-build/.stamp-win32-install : win-build/.stamp-win32-configure
+	(cd win-build/libogg-$(ogg_version) && make clean all check install)
+	touch $@
+
+win-build/.stamp-win32-configure : win-build/.stamp-source
+	mkdir -p $(win_build)/win32
+	(cd win-build/libogg-$(ogg_version) && ./configure --prefix=$(win_build)/ogg32 $(win32_target) --disable-shared)
+	touch $@
+
+win-build/.stamp-source : win-build/.stamp-sha256sum-checked
+	(cd win-build && tar xf libogg-$(ogg_version).tar.gz)
+	touch $@
+
+#-------------------------------------------------------------------------------
+# Retrieve and check libogg tarball.
+
+win-build/.stamp-sha256sum-checked : win-build/libogg-$(ogg_version).tar.gz
+	@if test $$(sha256sum $+ | sed 's/ .*//') != $(ogg_sha256sum) ; then exit 1 ; fi
+	@echo "sha256 sum : ok"
+	touch $@
+
+win-build/libogg-$(ogg_version).tar.gz :
+	mkdir -p win-build
+	wget http://downloads.xiph.org/releases/ogg/$$(basename $@) -O $@
+
+#-------------------------------------------------------------------------------
+# Autotool stuff.
+
+configure : configure.ac autogen.sh
+	./autogen.sh
+
+clean :
+	rm -rf $(win_build) flac-$(flac_version)-win
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..491d355
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+# Run this to set up the build system: configure, makefiles, etc.
+# We trust that the user has a recent enough autoconf & automake setup
+# (not older than a few years...)
+
+use_symlinks=" --symlink"
+
+case $1 in
+	--no-symlink*)
+		use_symlinks=""
+		echo "Copying autotool files instead of using symlinks."
+		;;
+	*)
+		echo "Using symlinks to autotool files (use --no-symlinks to copy instead)."
+		;;
+	esac
+
+test_program_errors=0
+
+test_program () {
+	if ! command -v $1 >/dev/null 2>&1 ; then
+		echo "Missing program '$1'."
+		test_program_errors=1
+		fi
+}
+
+for prog in autoconf automake libtool pkg-config ; do
+	test_program $prog
+	done
+
+if test $(uname -s) != "Darwin" ; then
+	test_program gettext
+	fi
+
+test $test_program_errors -ne 1 || exit 1
+
+#-------------------------------------------------------------------------------
+
+set -e
+
+if test $(uname -s) = "OpenBSD" ; then
+	# OpenBSD needs these environment variables set.
+	if test -z "$AUTOCONF_VERSION" ; then
+		AUTOCONF_VERSION=2.69
+		export AUTOCONF_VERSION
+		echo "Defaulting to use AUTOCONF_VERSION version ${AUTOCONF_VERSION}."
+	else
+		echo "Using AUTOCONF_VERSION version ${AUTOCONF_VERSION}."
+		fi
+	if test -z "$AUTOMAKE_VERSION" ; then
+		AUTOMAKE_VERSION=1.15
+		export AUTOMAKE_VERSION
+		echo "Defaulting to use AUTOMAKE_VERSION version ${AUTOMAKE_VERSION}."
+	else
+		echo "Using AUTOMAKE_VERSION version ${AUTOMAKE_VERSION}."
+		fi
+	fi
+
+srcdir=`dirname $0`
+test -n "$srcdir" && cd "$srcdir"
+
+echo "Updating build configuration files for FLAC, please wait...."
+
+touch config.rpath
+autoreconf --install $use_symlinks --force
+#./configure "$@" && echo
diff --git a/build/Makefile.am b/build/Makefile.am
new file mode 100644
index 0000000..4d21ba9
--- /dev/null
+++ b/build/Makefile.am
@@ -0,0 +1,23 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+	compile.mk \
+	config.mk \
+	exe.mk \
+	lib.mk
diff --git a/build/compile.mk b/build/compile.mk
new file mode 100644
index 0000000..121080a
--- /dev/null
+++ b/build/compile.mk
@@ -0,0 +1,49 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU makefile fragment for building a library
+#
+
+%.debug.o %.release.o : %.c
+	$(CC) $(CFLAGS) -c $< -o $@
+%.debug.o %.release.o : %.cc
+	$(CCC) $(CXXFLAGS) -c $< -o $@
+%.debug.o %.release.o : %.cpp
+	$(CCC) $(CXXFLAGS) -c $< -o $@
+%.debug.pic.o %.release.pic.o : %.c
+	$(CC) $(CFLAGS) $(F_PIC) -DPIC -c $< -o $@
+%.debug.pic.o %.release.pic.o : %.cc
+	$(CCC) $(CXXFLAGS) $(F_PIC) -DPIC -c $< -o $@
+%.debug.pic.o %.release.pic.o : %.cpp
+	$(CCC) $(CXXFLAGS) $(F_PIC) -DPIC -c $< -o $@
+%.debug.i %.release.i : %.c
+	$(CC) $(CFLAGS) -E $< -o $@
+%.debug.i %.release.i : %.cc
+	$(CCC) $(CXXFLAGS) -E $< -o $@
+%.debug.i %.release.i : %.cpp
+	$(CCC) $(CXXFLAGS) -E $< -o $@
+
+%.debug.o : %.nasm
+	$(NASM) -f elf -d OBJ_FORMAT_elf -i ia32/ -g $< -o $@
+%.release.o : %.nasm
+	$(NASM) -f elf -d OBJ_FORMAT_elf -i ia32/ $< -o $@
+%.debug.pic.o : %.nasm
+	$(NASM) -f elf -d OBJ_FORMAT_elf -i ia32/ -g $< -o $@
+%.release.pic.o : %.nasm
+	$(NASM) -f elf -d OBJ_FORMAT_elf -i ia32/ $< -o $@
diff --git a/build/config.mk b/build/config.mk
new file mode 100644
index 0000000..09abbbd
--- /dev/null
+++ b/build/config.mk
@@ -0,0 +1,159 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# customizable settings from the make invocation
+#
+
+USE_OGG     ?= 1
+USE_ICONV   ?= 1
+USE_LROUND  ?= 1
+USE_FSEEKO  ?= 1
+USE_LANGINFO_CODESET ?= 1
+
+#
+# debug/release selection
+#
+
+DEFAULT_BUILD = release
+
+F_PIC := -fPIC
+
+# returns Linux, Darwin, FreeBSD, etc.
+ifndef OS
+    OS := $(shell uname -s)
+endif
+# returns i386, x86_64, powerpc, etc.
+ifndef PROC
+    ifeq ($(findstring Windows,$(OS)),Windows)
+        PROC := i386 # failsafe
+        # ifeq ($(findstring i686,$(shell gcc -dumpmachine)),i686) # MinGW-w64: i686-w64-mingw32
+        ifeq ($(findstring x86_64,$(shell gcc -dumpmachine)),x86_64) # MinGW-w64: x86_64-w64-mingw32
+            PROC := x86_64
+        endif
+    else
+        ifeq ($(shell uname -p),amd64)
+            PROC := x86_64
+        else
+            PROC := $(shell uname -p)
+        endif
+    endif
+endif
+ifeq ($(PROC),powerpc)
+    PROC := ppc
+endif
+# x64_64 Mac OS outputs 'i386' in uname -p; use uname -m instead
+ifeq ($(PROC),i386)
+    ifeq ($(OS),Darwin)
+        PROC := $(shell uname -m)
+    endif
+endif
+
+ifeq ($(OS),Linux)
+    PROC := $(shell uname -m)
+    USE_ICONV := 0
+endif
+
+ifeq ($(findstring Windows,$(OS)),Windows)
+    F_PIC :=
+    USE_ICONV := 0
+    USE_LANGINFO_CODESET := 0
+    ifeq (mingw32,$(shell gcc -dumpmachine)) # MinGW (mainline): mingw32
+        USE_FSEEKO := 0
+    endif
+endif
+
+debug    : BUILD = debug
+valgrind : BUILD = debug
+release  : BUILD = release
+
+# override LINKAGE on OS X until we figure out how to get 'cc -static' to work
+ifeq ($(OS),Darwin)
+LINKAGE = -arch $(PROC)
+else
+debug    : LINKAGE = -static
+valgrind : LINKAGE = -dynamic
+release  : LINKAGE = -static
+endif
+
+all default: $(DEFAULT_BUILD)
+
+#
+# GNU makefile fragment for emulating stuff normally done by configure
+#
+
+VERSION=\"1.3.3\"
+
+CONFIG_CFLAGS=$(CUSTOM_CFLAGS) -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DHAVE_CXX_VARARRAYS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+ifeq ($(OS),Darwin)
+    CONFIG_CFLAGS += -DFLAC__SYS_DARWIN -DHAVE_SYS_PARAM_H -arch $(PROC)
+else
+    CONFIG_CFLAGS += -DHAVE_SOCKLEN_T
+endif
+
+ifeq ($(PROC),ppc)
+    CONFIG_CFLAGS += -DWORDS_BIGENDIAN=1 -DCPU_IS_LITTLE_ENDIAN=0
+else
+    CONFIG_CFLAGS += -DWORDS_BIGENDIAN=0 -DCPU_IS_LITTLE_ENDIAN=1
+endif
+
+ifeq ($(OS),Linux)
+	ifeq ($(PROC),x86_64)
+        CONFIG_CFLAGS += -fPIC
+	endif
+endif
+ifeq ($(OS),FreeBSD)
+    CONFIG_CFLAGS += -DHAVE_SYS_PARAM_H
+endif
+
+ifneq (0,$(USE_ICONV))
+    CONFIG_CFLAGS += -DHAVE_ICONV
+    ICONV_LIBS = -liconv
+else
+    ICONV_LIBS =
+endif
+
+ifneq (0,$(USE_OGG))
+    CONFIG_CFLAGS += -DFLAC__HAS_OGG=1
+    OGG_INCLUDES = -I$(OGG_INCLUDE_DIR)
+    OGG_EXPLICIT_LIBS = $(OGG_LIB_DIR)/libogg.a
+    OGG_LIBS = -L$(OGG_LIB_DIR) -logg
+    OGG_SRCS = $(OGG_SRCS_C)
+else
+    CONFIG_CFLAGS += -DFLAC__HAS_OGG=0
+    OGG_INCLUDES =
+    OGG_EXPLICIT_LIBS =
+    OGG_LIBS =
+    OGG_SRCS =
+endif
+
+OGG_INCLUDE_DIR=$(HOME)/local/include
+OGG_LIB_DIR=$(HOME)/local/lib
+
+ifneq (0,$(USE_LROUND))
+    CONFIG_CFLAGS += -DHAVE_LROUND
+endif
+
+ifneq (0,$(USE_FSEEKO))
+    CONFIG_CFLAGS += -DHAVE_FSEEKO
+endif
+
+ifneq (0,$(USE_LANGINFO_CODESET))
+    CONFIG_CFLAGS += -DHAVE_LANGINFO_CODESET
+endif
diff --git a/build/exe.mk b/build/exe.mk
new file mode 100644
index 0000000..1ff6d2d
--- /dev/null
+++ b/build/exe.mk
@@ -0,0 +1,107 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU makefile fragment for building an executable
+#
+
+include $(topdir)/build/config.mk
+
+ifeq ($(OS),Darwin)
+    CC          = cc
+    CCC         = c++
+else
+ifeq ($(OS),FreeBSD)
+    CC          = cc
+    CCC         = c++
+else
+    CC          = gcc
+    CCC         = g++
+endif
+endif
+ifeq ($(CC),gcc)
+    GCC_INLINE  = -finline-functions
+endif
+NASM        = nasm
+LINK        = $(CC) $(LINKAGE)
+OBJPATH     = $(topdir)/objs
+BINPATH     = $(OBJPATH)/$(BUILD)/bin
+LIBPATH     = $(OBJPATH)/$(BUILD)/lib
+DEBUG_BINPATH   = $(OBJPATH)/debug/bin
+DEBUG_LIBPATH   = $(OBJPATH)/debug/lib
+RELEASE_BINPATH = $(OBJPATH)/release/bin
+RELEASE_LIBPATH = $(OBJPATH)/release/lib
+PROGRAM         = $(BINPATH)/$(PROGRAM_NAME)
+DEBUG_PROGRAM   = $(DEBUG_BINPATH)/$(PROGRAM_NAME)
+RELEASE_PROGRAM = $(RELEASE_BINPATH)/$(PROGRAM_NAME)
+
+BASE_CFLAGS = -Wall -Wextra $(CONFIG_CFLAGS) -DVERSION=$(VERSION) $(DEFINES) $(INCLUDES)
+
+ifeq ($(DEFAULT_BUILD),debug)
+CFLAGS   := -g -O0 -DDEBUG $(CFLAGS) $(BASE_CFLAGS) -Wmissing-prototypes -Wstrict-prototypes
+CXXFLAGS := -g -O0 -DDEBUG $(CXXFLAGS) $(BASE_CFLAGS)
+endif
+
+ifeq ($(DEFAULT_BUILD),valgrind)
+CFLAGS   := -g -O0 -DDEBUG  -DDEBUG -DFLAC__VALGRIND_TESTING $(CFLAGS) $(BASE_CFLAGS) -Wmissing-prototypes -Wstrict-prototypes
+CXXFLAGS := -g -O0 -DDEBUG -DDEBUG -DFLAC__VALGRIND_TESTING $(CXXFLAGS) $(BASE_CFLAGS)
+endif
+
+ifeq ($(DEFAULT_BUILD),release)
+CFLAGS   := -O3 -fomit-frame-pointer -funroll-loops $(GCC_INLINE) -DFLaC__INLINE=__inline__ -DNDEBUG $(CFLAGS) $(BASE_CFLAGS) -Wmissing-prototypes -Wstrict-prototypes
+CXXFLAGS := -O3 -fomit-frame-pointer -funroll-loops $(GCC_INLINE) -DFLaC__INLINE=__inline__ -DNDEBUG $(CXXFLAGS) $(BASE_CFLAGS)
+endif
+
+LFLAGS   = -L$(LIBPATH)
+
+DEBUG_OBJS = $(SRCS_C:%.c=%.debug.o) $(SRCS_CC:%.cc=%.debug.o) $(SRCS_CPP:%.cpp=%.debug.o) $(SRCS_NASM:%.nasm=%.debug.o)
+RELEASE_OBJS = $(SRCS_C:%.c=%.release.o) $(SRCS_CC:%.cc=%.release.o) $(SRCS_CPP:%.cpp=%.release.o) $(SRCS_NASM:%.nasm=%.release.o)
+ifeq ($(PROC),x86_64)
+DEBUG_PIC_OBJS = $(SRCS_C:%.c=%.debug.pic.o) $(SRCS_CC:%.cc=%.debug.pic.o) $(SRCS_CPP:%.cpp=%.debug.pic.o) $(SRCS_NASM:%.nasm=%.debug.pic.o)
+RELEASE_PIC_OBJS = $(SRCS_C:%.c=%.release.pic.o) $(SRCS_CC:%.cc=%.release.pic.o) $(SRCS_CPP:%.cpp=%.release.pic.o) $(SRCS_NASM:%.nasm=%.release.pic.o)
+endif
+
+debug   : $(DEBUG_PROGRAM)
+valgrind: $(DEBUG_PROGRAM)
+release : $(RELEASE_PROGRAM)
+
+# by default on OS X we link with static libs as much as possible
+
+$(DEBUG_PROGRAM) : $(DEBUG_OBJS) $(DEBUG_PIC_OBJS)
+ifeq ($(OS),Darwin)
+	$(LINK) -o $@ $(DEBUG_OBJS) $(EXPLICIT_LIBS)
+else
+	$(LINK) -o $@ $(DEBUG_OBJS) $(LFLAGS) $(LIBS)
+endif
+
+$(RELEASE_PROGRAM) : $(RELEASE_OBJS) $(RELEASE_PIC_OBJS)
+ifeq ($(OS),Darwin)
+	$(LINK) -o $@ $(RELEASE_OBJS) $(EXPLICIT_LIBS)
+else
+	$(LINK) -o $@ $(RELEASE_OBJS) $(LFLAGS) $(LIBS)
+endif
+
+include $(topdir)/build/compile.mk
+
+.PHONY : clean
+clean :
+	-rm -f $(DEBUG_OBJS) $(RELEASE_OBJS) $(DEBUG_PIC_OBJS) $(RELEASE_PIC_OBJS) $(OBJPATH)/*/bin/$(PROGRAM_NAME)
+
+.PHONY : depend
+depend:
+	makedepend -fMakefile.lite -- $(CFLAGS) $(INCLUDES) -- *.c *.cc *.cpp
diff --git a/build/lib.mk b/build/lib.mk
new file mode 100644
index 0000000..12bcb41
--- /dev/null
+++ b/build/lib.mk
@@ -0,0 +1,138 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU makefile fragment for building a library
+#
+
+include $(topdir)/build/config.mk
+
+ifeq ($(OS),Darwin)
+    CC          = cc
+    CCC         = c++
+else
+ifeq ($(OS),FreeBSD)
+    CC          = cc
+    CCC         = c++
+else
+    CC          = gcc
+    CCC         = g++
+endif
+endif
+ifeq ($(CC),gcc)
+    GCC_INLINE  = -finline-functions
+endif
+NASM        = nasm
+LINK        = ar cr
+OBJPATH     = $(topdir)/objs
+LIBPATH     = $(OBJPATH)/$(BUILD)/lib
+DEBUG_LIBPATH     = $(OBJPATH)/debug/lib
+RELEASE_LIBPATH   = $(OBJPATH)/release/lib
+ifeq ($(OS),Darwin)
+    STATIC_LIB_SUFFIX = a
+    DYNAMIC_LIB_SUFFIX = dylib
+else
+ifeq ($(findstring Windows,$(OS)),Windows)
+    STATIC_LIB_SUFFIX = a
+    DYNAMIC_LIB_SUFFIX = dll
+else
+    STATIC_LIB_SUFFIX = a
+    DYNAMIC_LIB_SUFFIX = so
+endif
+endif
+STATIC_LIB_NAME     = $(LIB_NAME).$(STATIC_LIB_SUFFIX)
+DYNAMIC_LIB_NAME    = $(LIB_NAME).$(DYNAMIC_LIB_SUFFIX)
+STATIC_LIB          = $(LIBPATH)/$(STATIC_LIB_NAME)
+DYNAMIC_LIB         = $(LIBPATH)/$(DYNAMIC_LIB_NAME)
+DEBUG_STATIC_LIB    = $(DEBUG_LIBPATH)/$(STATIC_LIB_NAME)
+DEBUG_DYNAMIC_LIB   = $(DEBUG_LIBPATH)/$(DYNAMIC_LIB_NAME)
+RELEASE_STATIC_LIB  = $(RELEASE_LIBPATH)/$(STATIC_LIB_NAME)
+RELEASE_DYNAMIC_LIB = $(RELEASE_LIBPATH)/$(DYNAMIC_LIB_NAME)
+ifeq ($(OS),Darwin)
+    LINKD       = $(CC) -dynamiclib -flat_namespace -undefined suppress -install_name $(DYNAMIC_LIB)
+else
+    LINKD       = $(CC) -shared
+endif
+
+BASE_CFLAGS = -Wall -Wextra $(CONFIG_CFLAGS) -DVERSION=$(VERSION) -DPACKAGE_VERSION=$(VERSION) $(DEFINES) $(INCLUDES)
+
+ifeq ($(DEFAULT_BUILD),debug)
+CFLAGS   := -g -O0 -DDEBUG $(CFLAGS) $(BASE_CFLAGS) -Wmissing-prototypes -Wstrict-prototypes
+CXXFLAGS := -g -O0 -DDEBUG $(CFLAGS) $(BASE_CFLAGS)
+endif
+
+ifeq ($(DEFAULT_BUILD),valgrind)
+CFLAGS   := -g -O0 -DDEBUG  -DDEBUG -DFLAC__VALGRIND_TESTING $(CFLAGS) $(BASE_CFLAGS) -Wmissing-prototypes -Wstrict-prototypes
+CXXFLAGS := -g -O0 -DDEBUG -DDEBUG -DFLAC__VALGRIND_TESTING $(CFLAGS) $(BASE_CFLAGS)
+endif
+
+ifeq ($(DEFAULT_BUILD),release)
+CFLAGS   := -O3 -fomit-frame-pointer -funroll-loops $(GCC_INLINE) -DFLaC__INLINE=__inline__ -DNDEBUG $(CFLAGS) $(BASE_CFLAGS) -Wmissing-prototypes -Wstrict-prototypes
+CXXFLAGS := -O3 -fomit-frame-pointer -funroll-loops $(GCC_INLINE) -DFLaC__INLINE=__inline__ -DNDEBUG $(CFLAGS) $(BASE_CFLAGS)
+endif
+
+LFLAGS   = -L$(LIBPATH)
+
+DEBUG_OBJS = $(SRCS_C:%.c=%.debug.o) $(SRCS_CC:%.cc=%.debug.o) $(SRCS_CPP:%.cpp=%.debug.o) $(SRCS_NASM:%.nasm=%.debug.o)
+RELEASE_OBJS = $(SRCS_C:%.c=%.release.o) $(SRCS_CC:%.cc=%.release.o) $(SRCS_CPP:%.cpp=%.release.o) $(SRCS_NASM:%.nasm=%.release.o)
+ifeq ($(PROC),x86_64)
+DEBUG_PIC_OBJS = $(SRCS_C:%.c=%.debug.pic.o) $(SRCS_CC:%.cc=%.debug.pic.o) $(SRCS_CPP:%.cpp=%.debug.pic.o) $(SRCS_NASM:%.nasm=%.debug.pic.o)
+RELEASE_PIC_OBJS = $(SRCS_C:%.c=%.release.pic.o) $(SRCS_CC:%.cc=%.release.pic.o) $(SRCS_CPP:%.cpp=%.release.pic.o) $(SRCS_NASM:%.nasm=%.release.pic.o)
+endif
+
+debug   : $(DEBUG_STATIC_LIB) $(DEBUG_DYNAMIC_LIB)
+valgrind: $(DEBUG_STATIC_LIB) $(DEBUG_DYNAMIC_LIB)
+release : $(RELEASE_STATIC_LIB) $(RELEASE_DYNAMIC_LIB)
+
+$(DEBUG_STATIC_LIB): $(DEBUG_OBJS)
+	$(LINK) $@ $(DEBUG_OBJS) && ranlib $@
+
+$(RELEASE_STATIC_LIB): $(RELEASE_OBJS)
+	$(LINK) $@ $(RELEASE_OBJS) && ranlib $@
+
+$(DEBUG_DYNAMIC_LIB) : $(DEBUG_OBJS) $(DEBUG_PIC_OBJS)
+ifeq ($(OS),Darwin)
+	echo Not building dynamic lib, command is: $(LINKD) -o $@ $(DEBUG_OBJS) $(LFLAGS) $(LIBS) -lc
+else
+ifeq ($(PROC),x86_64)
+	$(LINKD) -o $@ $(DEBUG_PIC_OBJS) $(LFLAGS) $(LIBS)
+else
+	$(LINKD) -o $@ $(DEBUG_OBJS) $(LFLAGS) $(LIBS)
+endif
+endif
+
+$(RELEASE_DYNAMIC_LIB) : $(RELEASE_OBJS) $(RELEASE_PIC_OBJS)
+ifeq ($(OS),Darwin)
+	echo Not building dynamic lib, command is: $(LINKD) -o $@ $(RELEASE_OBJS) $(LFLAGS) $(LIBS) -lc
+else
+ifeq ($(PROC),x86_64)
+	$(LINKD) -o $@ $(RELEASE_PIC_OBJS) $(LFLAGS) $(LIBS)
+else
+	$(LINKD) -o $@ $(RELEASE_OBJS) $(LFLAGS) $(LIBS)
+endif
+endif
+
+include $(topdir)/build/compile.mk
+
+.PHONY : clean
+clean :
+	-rm -f $(DEBUG_OBJS) $(RELEASE_OBJS) $(DEBUG_PIC_OBJS) $(RELEASE_PIC_OBJS) $(OBJPATH)/*/lib/$(STATIC_LIB_NAME) $(OBJPATH)/*/lib/$(DYNAMIC_LIB_NAME)
+
+.PHONY : depend
+depend:
+	makedepend -fMakefile.lite -- $(CFLAGS) $(INCLUDES) -- *.c *.cc *.cpp
diff --git a/ci/flac-autotool.sh b/ci/flac-autotool.sh
new file mode 100755
index 0000000..dafe29f
--- /dev/null
+++ b/ci/flac-autotool.sh
@@ -0,0 +1,17 @@
+# Continuous integration build script for FLAC.
+# This script is run by automated frameworks to verify commits
+# see https://mf4.xiph.org/jenkins/job/flac/
+
+# This is intended to be run from the top-level source directory.
+
+set -x
+
+./autogen.sh
+
+./configure
+
+# Should do 'distcheck' here instead of 'check', but 'distcheck' is currently busted.
+V=1 make clean distcheck
+
+# Since we're doing 'make distcheck' we remove the generated source tarball.
+rm -f flac-*.tar.xz
diff --git a/cmake/CheckCPUArch.c.in b/cmake/CheckCPUArch.c.in
new file mode 100644
index 0000000..5493139
--- /dev/null
+++ b/cmake/CheckCPUArch.c.in
@@ -0,0 +1,7 @@
+int main(void) {
+#if @CHECK_CPU_ARCH_DEFINES@
+    return 0;
+#else
+    fail
+#endif
+}
diff --git a/cmake/CheckCPUArch.cmake b/cmake/CheckCPUArch.cmake
new file mode 100644
index 0000000..95330b4
--- /dev/null
+++ b/cmake/CheckCPUArch.cmake
@@ -0,0 +1,23 @@
+macro(_CHECK_CPU_ARCH ARCH ARCH_DEFINES VARIABLE)
+    if(NOT DEFINED HAVE_${VARIABLE})
+        message(STATUS "Check CPU architecture is ${ARCH}")
+        set(CHECK_CPU_ARCH_DEFINES ${ARCH_DEFINES})
+        configure_file(${PROJECT_SOURCE_DIR}/cmake/CheckCPUArch.c.in ${PROJECT_BINARY_DIR}/CMakeFiles/CMakeTmp/CheckCPUArch.c @ONLY)
+        try_compile(HAVE_${VARIABLE} "${PROJECT_BINARY_DIR}"
+            "${PROJECT_BINARY_DIR}/CMakeFiles/CMakeTmp/CheckCPUArch.c")
+        if(HAVE_${VARIABLE})
+            message(STATUS "Check CPU architecture is ${ARCH} - yes")
+            set(${VARIABLE} 1 CACHE INTERNAL "Result of CHECK_CPU_ARCH_X64" FORCE)
+        else ()
+            message(STATUS "Check CPU architecture is ${ARCH} - no")
+        endif()
+    endif ()
+endmacro(_CHECK_CPU_ARCH)
+
+macro(CHECK_CPU_ARCH_X64 VARIABLE)
+    _CHECK_CPU_ARCH(x64 "defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)" ${VARIABLE})
+endmacro(CHECK_CPU_ARCH_X64)
+
+macro(CHECK_CPU_ARCH_X86 VARIABLE)
+    _CHECK_CPU_ARCH(x86 "defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)" ${VARIABLE})
+endmacro(CHECK_CPU_ARCH_X86)
diff --git a/cmake/FindOgg.cmake b/cmake/FindOgg.cmake
new file mode 100644
index 0000000..b60c352
--- /dev/null
+++ b/cmake/FindOgg.cmake
@@ -0,0 +1,26 @@
+find_package(PkgConfig)
+pkg_check_modules(_OGG QUIET ogg)
+
+find_path(OGG_INCLUDE_DIR
+    NAMES "ogg/ogg.h"
+    PATHS ${_OGG_INCLUDE_DIRS})
+
+find_library(OGG_LIBRARY
+    NAMES ogg libogg
+    HINTS ${_OGG_LIBRARY_DIRS})
+
+mark_as_advanced(
+    OGG_INCLUDE_DIR
+    OGG_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Ogg
+    REQUIRED_VARS OGG_INCLUDE_DIR OGG_LIBRARY
+    VERSION_VAR _OGG_VERSION)
+
+if(OGG_FOUND AND NOT TARGET Ogg::ogg)
+    add_library(Ogg::ogg UNKNOWN IMPORTED)
+    set_target_properties(Ogg::ogg PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${OGG_INCLUDE_DIR}"
+        IMPORTED_LOCATION "${OGG_LIBRARY}")
+endif()
diff --git a/cmake/UseSystemExtensions.cmake b/cmake/UseSystemExtensions.cmake
new file mode 100644
index 0000000..f3c9490
--- /dev/null
+++ b/cmake/UseSystemExtensions.cmake
@@ -0,0 +1,73 @@
+include(CheckCSourceCompiles)
+
+check_c_source_compiles("
+    int main()
+    {
+    #ifndef _FORTIFY_SOURCE
+        return 0;
+    #else
+        this_is_an_error;
+    #endif
+    }"
+    DODEFINE_FORTIFY_SOURCE)
+check_c_source_compiles("
+    #include <wchar.h>
+    mbstate_t x;
+    int main() { return 0; }"
+    HAVE_MBSTATE)
+if(NOT HAVE_MBSTATE)
+    check_c_source_compiles("
+        #define _XOPEN_SOURCE 500
+        #include <wchar.h>
+        mbstate_t x;
+        int main() { return 0; }"
+        DODEFINE_XOPEN_SOURCE)
+endif()
+check_c_source_compiles("
+    #define __EXTENSIONS__ 1
+    #include <stdio.h>
+    #ifdef HAVE_SYS_TYPES_H
+    # include <sys/types.h>
+    #endif
+    #ifdef HAVE_SYS_STAT_H
+    # include <sys/stat.h>
+    #endif
+    #ifdef STDC_HEADERS
+    # include <stdlib.h>
+    # include <stddef.h>
+    #else
+    # ifdef HAVE_STDLIB_H
+    #  include <stdlib.h>
+    # endif
+    #endif
+    #ifdef HAVE_STRING_H
+    # if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+    #  include <memory.h>
+    # endif
+    # include <string.h>
+    #endif
+    #ifdef HAVE_STRINGS_H
+    # include <strings.h>
+    #endif
+    #ifdef HAVE_INTTYPES_H
+    # include <inttypes.h>
+    #endif
+    #ifdef HAVE_STDINT_H
+    # include <stdint.h>
+    #endif
+    #ifdef HAVE_UNISTD_H
+    # include <unistd.h>
+    #endif
+    int main() { return 0; }"
+    DODEFINE_EXTENSIONS)
+
+add_definitions(
+    -D_DARWIN_C_SOURCE
+    -D_POSIX_PTHREAD_SEMANTICS
+    -D__STDC_WANT_IEC_60559_BFP_EXT__
+    -D__STDC_WANT_IEC_60559_DFP_EXT__
+    -D__STDC_WANT_IEC_60559_FUNCS_EXT__
+    -D__STDC_WANT_IEC_60559_TYPES_EXT__
+    -D__STDC_WANT_LIB_EXT2__
+    -D__STDC_WANT_MATH_SPEC_FUNCS__
+    -D_TANDEM_SOURCE)
diff --git a/config.cmake.h.in b/config.cmake.h.in
new file mode 100644
index 0000000..1d96f42
--- /dev/null
+++ b/config.cmake.h.in
@@ -0,0 +1,234 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#cmakedefine AC_APPLE_UNIVERSAL_BUILD
+
+/* Target processor is big endian. */
+#cmakedefine01 CPU_IS_BIG_ENDIAN
+
+/* Target processor is little endian. */
+#cmakedefine01 CPU_IS_LITTLE_ENDIAN
+
+/* Set FLAC__BYTES_PER_WORD to 8 (4 is the default) */
+#cmakedefine01 ENABLE_64_BIT_WORDS
+
+/* define to align allocated memory on 32-byte boundaries */
+#cmakedefine FLAC__ALIGN_MALLOC_DATA
+
+/* define if you have docbook-to-man or docbook2man */
+#cmakedefine FLAC__HAS_DOCBOOK_TO_MAN
+
+/* define if you are compiling for x86 and have the NASM assembler */
+#cmakedefine FLAC__HAS_NASM
+
+/* define if you have the ogg library */
+#cmakedefine01 OGG_FOUND
+#define FLAC__HAS_OGG OGG_FOUND
+
+/* define if compiler has __attribute__((target("cpu=power8"))) support */
+#cmakedefine FLAC__HAS_TARGET_POWER8
+
+/* define if compiler has __attribute__((target("cpu=power9"))) support */
+#cmakedefine FLAC__HAS_TARGET_POWER9
+
+/* Set to 1 if <x86intrin.h> is available. */
+#cmakedefine01 FLAC__HAS_X86INTRIN
+
+/* define if building for Darwin / MacOS X */
+#cmakedefine FLAC__SYS_DARWIN
+
+/* define if building for Linux */
+#cmakedefine FLAC__SYS_LINUX
+
+/* define to enable use of Altivec instructions */
+#cmakedefine FLAC__USE_ALTIVEC
+
+/* define to enable use of AVX instructions */
+#cmakedefine01 WITH_AVX
+#define FLAC__USE_AVX WITH_AVX
+
+/* define to enable use of VSX instructions */
+#cmakedefine FLAC__USE_VSX
+
+/* Compiler has the __builtin_bswap16 intrinsic */
+#cmakedefine01 HAVE_BSWAP16
+
+/* Compiler has the __builtin_bswap32 intrinsic */
+#cmakedefine01 HAVE_BSWAP32
+
+/* Define to 1 if you have the <byteswap.h> header file. */
+#cmakedefine HAVE_BYTESWAP_H
+
+/* define if you have clock_gettime */
+#cmakedefine HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the <cpuid.h> header file. */
+#cmakedefine HAVE_CPUID_H
+
+/* Define to 1 if C++ supports variable-length arrays. */
+#cmakedefine HAVE_CXX_VARARRAYS
+
+/* Define to 1 if C supports variable-length arrays. */
+#cmakedefine HAVE_C_VARARRAYS
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#cmakedefine HAVE_FSEEKO
+
+/* Define to 1 if you have the `getopt_long' function. */
+#cmakedefine HAVE_GETOPT_LONG
+
+/* Define if you have the iconv() function and it works. */
+#cmakedefine HAVE_ICONV
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine01 HAVE_INTTYPES_H
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#cmakedefine HAVE_LANGINFO_CODESET
+
+/* lround support */
+#cmakedefine01 HAVE_LROUND
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine HAVE_MEMORY_H
+
+/* Define to 1 if the system has the type `socklen_t'. */
+#cmakedefine HAVE_SOCKLEN_T
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine01 HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine HAVE_STDLIB_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#cmakedefine HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#cmakedefine HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#cmakedefine HAVE_TERMIOS_H
+
+/* Define to 1 if typeof works with your compiler. */
+#cmakedefine HAVE_TYPEOF
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H
+
+/* Define to 1 if you have the <x86intrin.h> header file. */
+#cmakedefine HAVE_X86INTRIN_H
+
+/* Define as const if the declaration of iconv() needs const. */
+#cmakedefine ICONV_CONST
+
+/* Define if debugging is disabled */
+#cmakedefine NDEBUG
+
+/* Name of package */
+#cmakedefine PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#cmakedefine PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#cmakedefine PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#cmakedefine PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#cmakedefine PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#cmakedefine PACKAGE_URL
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@PROJECT_VERSION@"
+
+/* The size of `off_t', as computed by sizeof. */
+#cmakedefine SIZEOF_OFF_T
+
+/* The size of `void*', as computed by sizeof. */
+#cmakedefine SIZEOF_VOIDP
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+#define _ALL_SOURCE
+#endif
+
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef _FORTIFY_SOURCE
+#cmakedefine DODEFINE_FORTIFY_SOURCE 2
+#define _FORTIFY_SOURCE DODEFINE_FORTIFY_SOURCE
+#endif
+
+#ifndef _XOPEN_SOURCE
+#cmakedefine DODEFINE_XOPEN_SOURCE 500
+#define _XOPEN_SOURCE DODEFINE_XOPEN_SOURCE
+#endif
+
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+#cmakedefine _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+#cmakedefine _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+#cmakedefine DODEFINE_EXTENSIONS
+#define __EXTENSIONS__ DODEFINE_EXTENSIONS
+#endif
+
+
+/* Target processor is big endian. */
+#define WORDS_BIGENDIAN CPU_IS_BIG_ENDIAN
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#ifndef _FILE_OFFSET_BITS
+# define _FILE_OFFSET_BITS 64
+#endif
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#ifndef _LARGEFILE_SOURCE
+# define _LARGEFILE_SOURCE
+#endif
+
+/* Define for large files, on AIX-style hosts. */
+#cmakedefine _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#cmakedefine _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#cmakedefine _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#cmakedefine _POSIX_SOURCE
+
+/* Define to __typeof__ if your compiler spells it that way. */
+#cmakedefine typeof
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..4a95cb8
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,634 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008,2009  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+# NOTE that for many of the AM_CONDITIONALs we use the prefix FLaC__
+# instead of FLAC__ since autoconf triggers off 'AC_' in strings
+
+AC_PREREQ(2.60)
+AC_INIT([flac], [1.3.3], [flac-dev@xiph.org], [flac], [https://www.xiph.org/flac/])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_SRCDIR([src/flac/main.c])
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([foreign 1.10 -Wall tar-pax no-dist-gzip dist-xz subdir-objects])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_MSG_CHECKING([whether configure should try to set CFLAGS/CXXFLAGS/CPPFLAGS/LDFLAGS])
+AS_IF([test "x${CFLAGS+set}" = "xset" || test "x${CXXFLAGS+set}" = "xset" || test "x${CPPFLAGS+set}" = "xset" || test "x${LDFLAGS+set}" = "xset"],
+	[enable_flags_setting=no],
+	[enable_flags_setting=yes]
+)
+AC_MSG_RESULT([${enable_flags_setting}])
+AX_CHECK_ENABLE_DEBUG
+user_cflags=$CFLAGS
+
+#Prefer whatever the current ISO standard is.
+AC_PROG_CC_STDC
+AC_USE_SYSTEM_EXTENSIONS
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+LT_INIT([win32-dll disable-static pic-only])
+AM_PROG_AS
+AC_PROG_CXX
+XIPH_C_COMPILER_IS_CLANG
+XIPH_GCC_REALLY_IS_GCC
+AC_PROG_MAKE_SET
+AC_PROG_MKDIR_P
+
+AC_SYS_LARGEFILE
+AC_FUNC_FSEEKO
+
+AC_CHECK_SIZEOF(off_t,1)	# Fake default value.
+AC_CHECK_SIZEOF([void*])
+AC_SEARCH_LIBS([lround],[m], [AC_DEFINE(HAVE_LROUND,1,lround support)])
+
+AC_LANG_PUSH([C++])
+# c++ flavor first
+AC_C_VARARRAYS
+if test $ac_cv_c_vararrays = yes; then
+	AC_DEFINE([HAVE_CXX_VARARRAYS], 1, [Define to 1 if C++ supports variable-length arrays.])
+fi
+AC_LANG_POP([C++])
+
+# c flavor
+AC_HEADER_STDC
+AM_PROG_CC_C_O
+AC_C_INLINE
+AC_C_VARARRAYS
+AC_C_TYPEOF
+
+AC_CHECK_HEADERS([stdint.h inttypes.h byteswap.h sys/param.h sys/ioctl.h termios.h x86intrin.h cpuid.h])
+
+XIPH_C_BSWAP32
+XIPH_C_BSWAP16
+
+ac_cv_c_big_endian=0
+ac_cv_c_little_endian=0
+AC_C_BIGENDIAN([ac_cv_c_big_endian=1], [ac_cv_c_little_endian=1], [
+	AC_MSG_WARN([[*****************************************************************]])
+	AC_MSG_WARN([[*** Not able to determine endian-ness of target processor.       ]])
+	AC_MSG_WARN([[*** The constants CPU_IS_BIG_ENDIAN and CPU_IS_LITTLE_ENDIAN in  ]])
+	AC_MSG_WARN([[*** config.h may need to be hand editied.                        ]])
+	AC_MSG_WARN([[*****************************************************************]])
+])
+AC_DEFINE_UNQUOTED(CPU_IS_BIG_ENDIAN, ${ac_cv_c_big_endian},
+					[Target processor is big endian.])
+AC_DEFINE_UNQUOTED(CPU_IS_LITTLE_ENDIAN, ${ac_cv_c_little_endian},
+					[Target processor is little endian.])
+AC_DEFINE_UNQUOTED(WORDS_BIGENDIAN, ${ac_cv_c_big_endian},
+					[Target processor is big endian.])
+
+AC_ARG_ENABLE(asm-optimizations, AC_HELP_STRING([--disable-asm-optimizations], [Don't use any assembly optimization routines]), asm_opt=no, asm_opt=yes)
+dnl ' Terminate the damn single quote
+AM_CONDITIONAL(FLaC__NO_ASM, test "x$asm_opt" = xno)
+if test "x$asm_opt" = xno ; then
+AC_DEFINE(FLAC__NO_ASM)
+AH_TEMPLATE(FLAC__NO_ASM, [define to disable use of assembly code])
+fi
+
+# For the XMMS plugin.
+AC_CHECK_TYPES(socklen_t, [], [])
+
+dnl check for getopt in standard library
+dnl AC_CHECK_FUNCS(getopt_long , , [LIBOBJS="$LIBOBJS getopt.o getopt1.o"] )
+AC_CHECK_FUNCS(getopt_long, [], [])
+
+AC_CHECK_SIZEOF(void*,1)
+
+asm_optimisation=no
+case "$host_cpu" in
+	amd64|x86_64)
+		case "$host" in
+			*gnux32)
+				# x32 user space and 64 bit kernel.
+				cpu_x86_64=true
+				AC_DEFINE(FLAC__CPU_X86_64)
+				AH_TEMPLATE(FLAC__CPU_X86_64, [define if building for x86_64])
+				asm_optimisation=$asm_opt
+				;;
+			*)
+				if test $ac_cv_sizeof_voidp = 4 ; then
+					# This must be a 32 bit user space running on 64 bit kernel so treat
+					# this as ia32.
+					cpu_ia32=true
+					AC_DEFINE(FLAC__CPU_IA32)
+					AH_TEMPLATE(FLAC__CPU_IA32, [define if building for ia32/i386])
+			else
+					# x86_64 user space and kernel.
+					cpu_x86_64=true
+					AC_DEFINE(FLAC__CPU_X86_64)
+					AH_TEMPLATE(FLAC__CPU_X86_64, [define if building for x86_64])
+				fi
+				asm_optimisation=$asm_opt
+				;;
+		esac
+		;;
+	i*86)
+		cpu_ia32=true
+		AC_DEFINE(FLAC__CPU_IA32)
+		AH_TEMPLATE(FLAC__CPU_IA32, [define if building for ia32/i386])
+		asm_optimisation=$asm_opt
+		;;
+	powerpc64|powerpc64le)
+		cpu_ppc64=true
+		cpu_ppc=true
+		AC_DEFINE(FLAC__CPU_PPC)
+		AH_TEMPLATE(FLAC__CPU_PPC, [define if building for PowerPC])
+		AC_DEFINE(FLAC__CPU_PPC64)
+		AH_TEMPLATE(FLAC__CPU_PPC64, [define if building for PowerPC64])
+		asm_optimisation=$asm_opt
+		;;
+	powerpc|powerpcle)
+		cpu_ppc=true
+		AC_DEFINE(FLAC__CPU_PPC)
+		AH_TEMPLATE(FLAC__CPU_PPC, [define if building for PowerPC])
+		asm_optimisation=$asm_opt
+		;;
+	sparc)
+		cpu_sparc=true
+		AC_DEFINE(FLAC__CPU_SPARC)
+		AH_TEMPLATE(FLAC__CPU_SPARC, [define if building for SPARC])
+		asm_optimisation=$asm_opt
+		;;
+esac
+AM_CONDITIONAL(FLAC__CPU_X86_64, test "x$cpu_x86_64" = xtrue)
+AM_CONDITIONAL(FLaC__CPU_IA32, test "x$cpu_ia32" = xtrue)
+AM_CONDITIONAL(FLaC__CPU_PPC, test "x$cpu_ppc" = xtrue)
+AM_CONDITIONAL(FLaC__CPU_PPC64, test "x$cpu_ppc64" = xtrue)
+AM_CONDITIONAL(FLaC__CPU_SPARC, test "x$cpu_sparc" = xtrue)
+
+if test "x$ac_cv_header_x86intrin_h" = xyes; then
+AC_DEFINE([FLAC__HAS_X86INTRIN], 1, [Set to 1 if <x86intrin.h> is available.])
+else
+AC_DEFINE([FLAC__HAS_X86INTRIN], 0)
+fi
+
+if test x"$cpu_ppc64" = xtrue ; then
+
+AC_C_ATTRIBUTE([target("cpu=power8")],
+  [have_cpu_power8=yes],
+  [have_cpu_power8=no])
+if test x"$have_cpu_power8" = xyes ; then
+  AC_DEFINE(FLAC__HAS_TARGET_POWER8)
+  AH_TEMPLATE(FLAC__HAS_TARGET_POWER8, [define if compiler has __attribute__((target("cpu=power8"))) support])
+fi
+
+AC_C_ATTRIBUTE([target("cpu=power9")],
+  [have_cpu_power9=yes],
+  [have_cpu_power9=no])
+if test x"$have_cpu_power9" = xyes ; then
+  AC_DEFINE(FLAC__HAS_TARGET_POWER9)
+  AH_TEMPLATE(FLAC__HAS_TARGET_POWER9, [define if compiler has __attribute__((target("cpu=power9"))) support])
+fi
+
+fi
+
+case "$host" in
+	i386-*-openbsd3.[[0-3]]) OBJ_FORMAT=aoutb ;;
+	*-*-cygwin|*mingw*) OBJ_FORMAT=win32 ;;
+	*-*-darwin*) OBJ_FORMAT=macho ;;
+	*emx*) OBJ_FORMAT=aout ;;
+	*djgpp) OBJ_FORMAT=coff ;;
+	*) OBJ_FORMAT=elf ;;
+esac
+AC_SUBST(OBJ_FORMAT)
+
+os_is_windows=no
+case "$host" in
+	*mingw*)
+		CPPFLAGS="-D__MSVCRT_VERSION__=0x0601 $CPPFLAGS"
+		os_is_windows=yes
+		;;
+esac
+
+AM_CONDITIONAL(OS_IS_WINDOWS, test "x$os_is_windows" = xyes)
+
+case "$host" in
+	*-linux-*)
+		sys_linux=true
+		AC_DEFINE(FLAC__SYS_LINUX)
+		AH_TEMPLATE(FLAC__SYS_LINUX, [define if building for Linux])
+		;;
+	*-*-darwin*)
+		sys_darwin=true
+		AC_DEFINE(FLAC__SYS_DARWIN)
+		AH_TEMPLATE(FLAC__SYS_DARWIN, [define if building for Darwin / MacOS X])
+		;;
+esac
+AM_CONDITIONAL(FLaC__SYS_DARWIN, test "x$sys_darwin" = xtrue)
+AM_CONDITIONAL(FLaC__SYS_LINUX, test "x$sys_linux" = xtrue)
+
+if test "x$cpu_ia32" = xtrue || test "x$cpu_x86_64" = xtrue ; then
+AC_DEFINE(FLAC__ALIGN_MALLOC_DATA)
+AH_TEMPLATE(FLAC__ALIGN_MALLOC_DATA, [define to align allocated memory on 32-byte boundaries])
+fi
+
+AM_CONDITIONAL([DEBUG], [test "x${ax_enable_debug}" = "xyes" || test "x${ax_enable_debug}" = "xinfo"])
+
+AC_ARG_ENABLE(sse,
+AC_HELP_STRING([--disable-sse], [Disable passing of -msse2 to the compiler]),
+[case "${enableval}" in
+	yes) sse_os=yes ;;
+	no)  sse_os=no ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-sse) ;;
+esac],[sse_os=yes])
+
+AC_ARG_ENABLE(altivec,
+AC_HELP_STRING([--disable-altivec], [Disable Altivec optimizations]),
+[case "${enableval}" in
+	yes) use_altivec=true ;;
+	no)  use_altivec=false ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-altivec) ;;
+esac],[use_altivec=true])
+AM_CONDITIONAL(FLaC__USE_ALTIVEC, test "x$use_altivec" = xtrue)
+if test "x$use_altivec" = xtrue ; then
+AC_DEFINE(FLAC__USE_ALTIVEC)
+AH_TEMPLATE(FLAC__USE_ALTIVEC, [define to enable use of Altivec instructions])
+fi
+
+AC_ARG_ENABLE(vsx,
+AC_HELP_STRING([--disable-vsx], [Disable VSX optimizations]),
+[case "${enableval}" in
+	yes) use_vsx=true ;;
+	no)  use_vsx=false ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-vsx) ;;
+esac],[use_vsx=true])
+AM_CONDITIONAL(FLaC__USE_VSX, test "x$use_vsx" = xtrue)
+if test "x$use_vsx" = xtrue ; then
+AC_DEFINE(FLAC__USE_VSX)
+AH_TEMPLATE(FLAC__USE_VSX, [define to enable use of VSX instructions])
+fi
+
+AC_ARG_ENABLE(avx,
+AC_HELP_STRING([--disable-avx], [Disable AVX, AVX2 optimizations]),
+[case "${enableval}" in
+	yes) use_avx=true ;;
+	no)  use_avx=false ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-avx) ;;
+esac],[use_avx=true])
+AM_CONDITIONAL(FLaC__USE_AVX, test "x$use_avx" = xtrue)
+if test "x$use_avx" = xtrue ; then
+AC_DEFINE(FLAC__USE_AVX)
+AH_TEMPLATE(FLAC__USE_AVX, [define to enable use of AVX instructions])
+fi
+
+AC_ARG_ENABLE(thorough-tests,
+AC_HELP_STRING([--disable-thorough-tests], [Disable thorough (long) testing, do only basic tests]),
+[case "${enableval}" in
+	yes) thorough_tests=true ;;
+	no)  thorough_tests=false ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-thorough-tests) ;;
+esac],[thorough_tests=true])
+AC_ARG_ENABLE(exhaustive-tests,
+AC_HELP_STRING([--enable-exhaustive-tests], [Enable exhaustive testing (VERY long)]),
+[case "${enableval}" in
+	yes) exhaustive_tests=true ;;
+	no)  exhaustive_tests=false ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-exhaustive-tests) ;;
+esac],[exhaustive_tests=false])
+if test "x$thorough_tests" = xfalse ; then
+FLAC__TEST_LEVEL=0
+elif test "x$exhaustive_tests" = xfalse ; then
+FLAC__TEST_LEVEL=1
+else
+FLAC__TEST_LEVEL=2
+fi
+AC_SUBST(FLAC__TEST_LEVEL)
+
+AC_ARG_ENABLE(werror,
+	AC_HELP_STRING([--enable-werror], [Enable -Werror in all Makefiles]))
+
+AC_ARG_ENABLE([stack-smash-protection],
+    [AS_HELP_STRING([--disable-stack-smash-protection],[Disable GNU GCC stack smash protection])],,
+    [AS_IF([test "$ac_cv_c_compiler_gnu" = "yes" && test "$os_is_windows" = "no"],
+        [enable_stack_smash_protection=yes],[enable_stack_smash_protection=no])])
+
+AC_ARG_ENABLE(64-bit-words,
+	AC_HELP_STRING([--enable-64-bit-words], [Set FLAC__BYTES_PER_WORD to 8 (4 is the default)]))
+if test "x$enable_64_bit_words" = xyes ; then
+	AC_DEFINE_UNQUOTED([ENABLE_64_BIT_WORDS],1,[Set FLAC__BYTES_PER_WORD to 8 (4 is the default)])
+else
+	AC_DEFINE_UNQUOTED([ENABLE_64_BIT_WORDS],0)
+	fi
+AC_SUBST(ENABLE_64_BIT_WORDS)
+
+AC_ARG_ENABLE(valgrind-testing,
+AC_HELP_STRING([--enable-valgrind-testing], [Run all tests inside Valgrind]),
+[case "${enableval}" in
+	yes) FLAC__TEST_WITH_VALGRIND=yes ;;
+	no)  FLAC__TEST_WITH_VALGRIND=no ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind-testing) ;;
+esac],[FLAC__TEST_WITH_VALGRIND=no])
+AC_SUBST(FLAC__TEST_WITH_VALGRIND)
+
+AC_ARG_ENABLE(doxygen-docs,
+AC_HELP_STRING([--disable-doxygen-docs], [Disable API documentation building via Doxygen]),
+[case "${enableval}" in
+	yes) enable_doxygen_docs=true ;;
+	no)  enable_doxygen_docs=false ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-doxygen-docs) ;;
+esac],[enable_doxygen_docs=true])
+if test "x$enable_doxygen_docs" != xfalse ; then
+	AC_CHECK_PROGS(DOXYGEN, doxygen)
+fi
+AM_CONDITIONAL(FLaC__HAS_DOXYGEN, test -n "$DOXYGEN")
+
+AC_ARG_ENABLE(local-xmms-plugin,
+AC_HELP_STRING([--enable-local-xmms-plugin], [Install XMMS plugin to ~/.xmms/Plugins instead of system location]),
+[case "${enableval}" in
+	yes) install_xmms_plugin_locally=true ;;
+	no)  install_xmms_plugin_locally=false ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-local-xmms-plugin) ;;
+esac],[install_xmms_plugin_locally=false])
+AM_CONDITIONAL(FLaC__INSTALL_XMMS_PLUGIN_LOCALLY, test "x$install_xmms_plugin_locally" = xtrue)
+
+AC_ARG_ENABLE(xmms-plugin,
+AC_HELP_STRING([--disable-xmms-plugin], [Do not build XMMS plugin]),
+[case "${enableval}" in
+	yes) enable_xmms_plugin=true ;;
+	no)  enable_xmms_plugin=false ;;
+	*) AC_MSG_ERROR(bad value ${enableval} for --enable-xmms-plugin) ;;
+esac],[enable_xmms_plugin=true])
+if test "x$enable_xmms_plugin" != xfalse ; then
+	AM_PATH_XMMS(0.9.5.1, , AC_MSG_WARN([*** XMMS >= 0.9.5.1 not installed - XMMS support will not be built]))
+fi
+AM_CONDITIONAL(FLaC__HAS_XMMS, test -n "$XMMS_INPUT_PLUGIN_DIR")
+
+dnl build FLAC++ or not
+AC_ARG_ENABLE([cpplibs],
+AC_HELP_STRING([--disable-cpplibs], [Do not build libFLAC++]),
+[case "${enableval}" in
+	yes) disable_cpplibs=false ;;
+	no)  disable_cpplibs=true ;;
+	*)   AC_MSG_ERROR(bad value ${enableval} for --enable-cpplibs) ;;
+esac], [disable_cpplibs=false])
+AM_CONDITIONAL(FLaC__WITH_CPPLIBS, [test "x$disable_cpplibs" != xtrue])
+
+AC_ARG_ENABLE([oss-fuzzers],
+  [AS_HELP_STRING([--enable-oss-fuzzers],
+    [Whether to generate the fuzzers for OSS-Fuzz (Clang only)])],
+  [have_oss_fuzzers=yes], [have_oss_fuzzers=no])
+
+if test "x$have_oss_fuzzers" = "xyes"; then
+  if test "x$xiph_cv_c_compiler_clang" = "xyes" ; then
+    AM_CONDITIONAL([USE_OSSFUZZERS], [test "x$have_oss_fuzzers" = "xyes"])
+    if test "x$LIB_FUZZING_ENGINE" = "x" ; then
+      # Only set this if it is empty.
+	  LIB_FUZZING_ENGINE=-fsanitize=fuzzer
+    fi
+  else
+    AM_CONDITIONAL([USE_OSSFUZZERS], [test "false" = "true"])
+    # Disable fuzzer if the compiler is not Clang.
+    AC_MSG_WARN([*** Ozz-Fuzz is disabled because that requres the  Clang compiler.])
+    have_oss_fuzzers="no (compiler is GCC)"
+  fi
+else
+  AM_CONDITIONAL([USE_OSSFUZZERS], [test "false" = "true"])
+fi
+
+AM_CONDITIONAL([USE_OSSFUZZ_FLAG], [test "x$LIB_FUZZING_ENGINE" = "x-fsanitize=fuzzer"])
+AM_CONDITIONAL([USE_OSSFUZZ_STATIC], [test -f "$LIB_FUZZING_ENGINE"])
+AC_SUBST([LIB_FUZZING_ENGINE])
+
+dnl check for ogg library
+AC_ARG_ENABLE([ogg],
+	AC_HELP_STRING([--disable-ogg], [Disable ogg support (default: test for libogg)]),
+	[ want_ogg=$enableval ], [ want_ogg=yes ] )
+
+if test "x$want_ogg" != "xno"; then
+	XIPH_PATH_OGG(have_ogg=yes, AC_MSG_WARN([*** Ogg development environment not installed - Ogg support will not be built]))
+fi
+
+FLAC__HAS_OGG=0
+AM_CONDITIONAL(FLaC__HAS_OGG, [test "x$have_ogg" = xyes])
+if test "x$have_ogg" = xyes ; then
+	FLAC__HAS_OGG=1
+	OGG_PACKAGE="ogg"
+else
+	have_ogg=no
+fi
+AC_DEFINE_UNQUOTED([FLAC__HAS_OGG],$FLAC__HAS_OGG,[define if you have the ogg library])
+AC_SUBST(FLAC__HAS_OGG)
+AC_SUBST(OGG_PACKAGE)
+
+dnl Build examples?
+AC_ARG_ENABLE([examples],
+	AS_HELP_STRING([--disable-examples], [Don't build and install examples]))
+AM_CONDITIONAL([EXAMPLES], [test "x$enable_examples" != "xno"])
+
+dnl check for i18n(internationalization); these are from libiconv/gettext
+AM_ICONV
+AM_LANGINFO_CODESET
+
+AC_CHECK_PROGS(DOCBOOK_TO_MAN, docbook-to-man docbook2man)
+AM_CONDITIONAL(FLaC__HAS_DOCBOOK_TO_MAN, test -n "$DOCBOOK_TO_MAN")
+if test -n "$DOCBOOK_TO_MAN" ; then
+AC_DEFINE(FLAC__HAS_DOCBOOK_TO_MAN)
+AH_TEMPLATE(FLAC__HAS_DOCBOOK_TO_MAN, [define if you have docbook-to-man or docbook2man])
+fi
+
+AC_CHECK_LIB(rt, clock_gettime,
+        LIB_CLOCK_GETTIME=-lrt
+        AC_DEFINE(HAVE_CLOCK_GETTIME)
+        AH_TEMPLATE(HAVE_CLOCK_GETTIME, [define if you have clock_gettime]))
+AC_SUBST(LIB_CLOCK_GETTIME)
+
+# only matters for x86
+AC_CHECK_PROGS(NASM, nasm)
+AM_CONDITIONAL(FLaC__HAS_NASM, test -n "$NASM")
+if test -n "$NASM" ; then
+AC_DEFINE(FLAC__HAS_NASM)
+AH_TEMPLATE(FLAC__HAS_NASM, [define if you are compiling for x86 and have the NASM assembler])
+fi
+
+dnl If debugging is disabled AND no CFLAGS/CXXFLAGS/CPPFLAGS/LDFLAGS
+dnl are provided, we can set defaults to our liking
+AS_IF([test "x${ax_enable_debug}" = "xno" && test "x${enable_flags_setting}" = "xyes"], [
+	CFLAGS="-O3 -funroll-loops"
+	CXXFLAGS="-O3"
+])
+
+XIPH_GCC_VERSION dnl Sets a non-zero GCC_XXX_VERSION for gcc, not clang. checks below rely on that..
+
+if test x$ac_cv_c_compiler_gnu = xyes -o x$xiph_cv_c_compiler_clang = xyes ; then
+	CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return -Wcast-align -Wnested-externs -Wshadow -Wundef -Wmissing-declarations -Winline " # -Wcast-qual -Wbad-function-cast -Wwrite-strings -Wconversion
+	CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wcast-align -Wshadow -Wwrite-strings -Wctor-dtor-privacy -Wnon-virtual-dtor -Wreorder -Wsign-promo -Wundef " # -Wcast-qual -Wbad-function-cast -Wwrite-strings -Woverloaded-virtual -Wmissing-declarations
+
+	XIPH_ADD_CFLAGS([-Wdeclaration-after-statement])
+
+	dnl some distributions (such as Gentoo) have _FORTIFY_SOURCE always
+	dnl enabled. We test for this situation in order to prevent polluting
+	dnl the console with messages of macro redefinitions.
+	AX_ADD_FORTIFY_SOURCE
+
+	AC_LANG_PUSH([C++])
+	XIPH_ADD_CXXFLAGS([-Weffc++])
+	AC_LANG_POP([C++])
+
+	if test x$xiph_cv_c_compiler_clang = xyes -a "$OBJ_FORMAT" = elf; then
+		CPPFLAGS="$CPPFLAGS -DFLAC__USE_VISIBILITY_ATTR"
+		CFLAGS="$CFLAGS -fvisibility=hidden"
+		CXXFLAGS="$CXXFLAGS -fvisibility=hidden"
+	elif test "$GCC_MAJOR_VERSION" -ge 4 && test "$OBJ_FORMAT" = elf; then
+		CPPFLAGS="$CPPFLAGS -DFLAC__USE_VISIBILITY_ATTR"
+		CFLAGS="$CFLAGS -fvisibility=hidden"
+		CXXFLAGS="$CXXFLAGS -fvisibility=hidden"
+		fi
+
+
+	if test x$xiph_cv_c_compiler_clang = xyes -a "$OBJ_FORMAT" = macho; then
+		CPPFLAGS="$CPPFLAGS -DFLAC__USE_VISIBILITY_ATTR"
+		CFLAGS="$CFLAGS -fvisibility=hidden"
+		CXXFLAGS="$CXXFLAGS -fvisibility=hidden"
+	elif test "$GCC_MAJOR_VERSION" -ge 4 && test "$OBJ_FORMAT" = macho; then
+		CPPFLAGS="$CPPFLAGS -DFLAC__USE_VISIBILITY_ATTR"
+		CFLAGS="$CFLAGS -fvisibility=hidden"
+		CXXFLAGS="$CXXFLAGS -fvisibility=hidden"
+		fi
+
+	if test "x$GCC_MAJOR_VERSION$GCC_MINOR_VERSION" = "x42" ; then
+		XIPH_ADD_CFLAGS([-fgnu89-inline])
+		fi
+
+	if test "x$GCC_MAJOR_VERSION$GCC_MINOR_VERSION" = "x47" ; then
+		XIPH_ADD_CFLAGS([-fno-inline-small-functions])
+		fi
+
+	if test "x$asm_optimisation$sse_os" = "xyesyes" ; then
+		XIPH_ADD_CFLAGS([-msse2])
+		fi
+
+	fi
+
+case "$host_os" in
+	"mingw32"|"os2")
+	if test "$host_cpu" = "i686"; then
+		XIPH_ADD_CFLAGS([-mstackrealign])
+		fi
+	esac
+
+if test x$enable_werror = "xyes" ; then
+	XIPH_ADD_CFLAGS([-Werror])
+	AC_LANG_PUSH([C++])
+	XIPH_ADD_CXXFLAGS([-Werror])
+	AC_LANG_POP([C++])
+	fi
+
+if test x$enable_stack_smash_protection = "xyes" ; then
+	XIPH_GCC_STACK_PROTECTOR
+	XIPH_GXX_STACK_PROTECTOR
+	fi
+
+AH_VERBATIM([FLAC_API_EXPORTS],
+[/* libtool defines DLL_EXPORT for windows dll builds,
+   but flac code relies on FLAC_API_EXPORTS instead. */
+#ifdef DLL_EXPORT
+#ifdef __cplusplus
+# define FLACPP_API_EXPORTS
+#else
+# define FLAC_API_EXPORTS
+#endif
+#endif])
+
+if test x$enable_shared != "xyes" ; then
+dnl for correct FLAC_API
+	CPPFLAGS="-DFLAC__NO_DLL $CPPFLAGS"
+	fi
+
+AC_CONFIG_FILES([ \
+	Makefile \
+	src/Makefile \
+	src/libFLAC/Makefile \
+	src/libFLAC/flac.pc \
+	src/libFLAC/ia32/Makefile \
+	src/libFLAC/include/Makefile \
+	src/libFLAC/include/private/Makefile \
+	src/libFLAC/include/protected/Makefile \
+	src/libFLAC++/Makefile \
+	src/libFLAC++/flac++.pc \
+	src/flac/Makefile \
+	src/metaflac/Makefile \
+	src/plugin_common/Makefile \
+	src/plugin_xmms/Makefile \
+	src/share/Makefile \
+	src/test_grabbag/Makefile \
+	src/test_grabbag/cuesheet/Makefile \
+	src/test_grabbag/picture/Makefile \
+	src/test_libs_common/Makefile \
+	src/test_libFLAC/Makefile \
+	src/test_libFLAC++/Makefile \
+	src/test_seeking/Makefile \
+	src/test_streams/Makefile \
+	src/utils/Makefile \
+	src/utils/flacdiff/Makefile \
+	src/utils/flactimer/Makefile \
+	examples/Makefile \
+	examples/c/Makefile \
+	examples/c/decode/Makefile \
+	examples/c/decode/file/Makefile \
+	examples/c/encode/Makefile \
+	examples/c/encode/file/Makefile \
+	examples/cpp/Makefile \
+	examples/cpp/decode/Makefile \
+	examples/cpp/decode/file/Makefile \
+	examples/cpp/encode/Makefile \
+	examples/cpp/encode/file/Makefile \
+	include/Makefile \
+	include/FLAC/Makefile \
+	include/FLAC++/Makefile \
+	include/share/Makefile \
+	include/share/grabbag/Makefile \
+	include/test_libs_common/Makefile \
+	doc/Doxyfile \
+	doc/Makefile \
+	doc/html/Makefile \
+	doc/html/images/Makefile \
+	m4/Makefile \
+	man/Makefile \
+	test/common.sh \
+	test/Makefile \
+	test/cuesheets/Makefile \
+	test/flac-to-flac-metadata-test-files/Makefile \
+	test/metaflac-test-files/Makefile \
+	test/pictures/Makefile \
+	build/Makefile \
+	microbench/Makefile \
+	oss-fuzz/Makefile
+])
+AC_OUTPUT
+
+AC_MSG_RESULT([
+-=-=-=-=-=-=-=-=-=-= Configuration Complete =-=-=-=-=-=-=-=-=-=-
+
+  Configuration summary :
+
+    FLAC version : ............................ ${VERSION}
+
+    Host CPU : ................................ ${host_cpu}
+    Host Vendor : ............................. ${host_vendor}
+    Host OS : ................................. ${host_os}
+])
+
+	echo "    Compiler is GCC : ......................... ${ac_cv_c_compiler_gnu}"
+if test x$ac_cv_c_compiler_gnu = xyes ; then
+	echo "    GCC version : ............................. ${GCC_VERSION}"
+fi
+	echo "    Compiler is Clang : ....................... ${xiph_cv_c_compiler_clang}"
+	echo "    SSE optimizations : ....................... ${sse_os}"
+	echo "    Asm optimizations : ....................... ${asm_optimisation}"
+	echo "    Ogg/FLAC support : ........................ ${have_ogg}"
+	echo "    Stack protector  : ........................ ${enable_stack_smash_protection}"
+	echo "    Fuzzing support (Clang only) : ............ ${have_oss_fuzzers}"
+echo
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..e0e3391
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,54 @@
+cmake_minimum_required(VERSION 3.9)
+
+find_package(Doxygen)
+
+if (NOT DOXYGEN_FOUND)
+    return()
+endif()
+
+option(BUILD_DOXYGEN "Enable API documentation building via Doxygen" ON)
+
+if (NOT BUILD_DOXYGEN)
+    return()
+endif()
+
+set(DOXYGEN_HTML_FOOTER doxygen.footer.html)
+set(DOXYGEN_GENERATE_TAGFILE FLAC.tag)
+
+if(CMAKE_VERSION VERSION_LESS 3.12)
+    doxygen_add_docs(FLAC-doxygen
+        ALL
+        "${PROJECT_SOURCE_DIR}/include/FLAC"
+        "${PROJECT_SOURCE_DIR}/include/FLAC++")
+else()
+    doxygen_add_docs(FLAC-doxygen
+        "${PROJECT_SOURCE_DIR}/include/FLAC"
+        "${PROJECT_SOURCE_DIR}/include/FLAC++")
+
+    install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/"
+        DESTINATION "${CMAKE_INSTALL_DOCDIR}/html/api")
+
+endif()
+
+install(FILES
+    html/images/logo.svg
+    html/images/logo130.gif
+    html/changelog.html
+    html/developers.html
+    html/documentation.html
+    html/documentation_bugs.html
+    html/documentation_example_code.html
+    html/documentation_format_overview.html
+    html/documentation_tools.html
+    html/documentation_tools_flac.html
+    html/documentation_tools_metaflac.html
+    html/faq.html
+    html/favicon.ico
+    html/features.html
+    html/flac.css
+    html/format.html
+    html/id.html
+    html/index.html
+    html/license.html
+    html/ogg_mapping.html
+DESTINATION "${CMAKE_INSTALL_DOCDIR}/html")
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000..cc20991
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,1784 @@
+# Doxyfile 1.7.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = FLAC
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1.3.3
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = Free Lossless Audio Codec
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doxytmp
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = NO
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = ..
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = "assert=\par Assertions:\n" \
+                         "default=\par Default Value:\n"
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = YES
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE      = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = YES
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = @top_srcdir@/include/FLAC \
+                         @top_srcdir@/include/FLAC++
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+#  for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            = @top_srcdir@/doc/doxygen.footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# style sheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the
+# mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = FLAC__NO_DLL
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      = FLAC_API \
+                         FLACPP_API
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = FLAC.tag
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..8e97259
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,41 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+SUBDIRS = . html
+
+if FLaC__HAS_DOXYGEN
+all-local: Doxyfile
+FLAC.tag: Doxyfile
+	doxygen Doxyfile
+	rm -rf html/api
+	mv doxytmp/html html/api
+	rm -rf doxytmp
+else
+FLAC.tag:
+	touch $@
+	mkdir -p html/api
+endif
+
+doc_DATA = \
+	FLAC.tag
+
+EXTRA_DIST = Doxyfile.in Makefile.lite doxygen.footer.html doxygen.header.html \
+	isoflac.txt $(doc_DATA) CMakeLists.txt
+
+distclean-local:
+	rm -rf FLAC.tag html/api doxytmp
diff --git a/doc/Makefile.lite b/doc/Makefile.lite
new file mode 100644
index 0000000..423824f
--- /dev/null
+++ b/doc/Makefile.lite
@@ -0,0 +1,29 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+topdir = ..
+
+FLAC.tag: Doxyfile
+	rm -rf doxytmp
+	doxygen Doxyfile
+	rm -rf html/api
+	mv doxytmp/html html/api
+	rm -rf doxytmp
+
+clean:
+	rm -rf FLAC.tag html/api doxytmp
diff --git a/doc/doxygen.footer.html b/doc/doxygen.footer.html
new file mode 100644
index 0000000..cce041d
--- /dev/null
+++ b/doc/doxygen.footer.html
@@ -0,0 +1,25 @@
+
+<hr size="1"/>
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+			<td width="1%" align="right">
+				<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=13478&amp;type=1" width="88" height="31" border="0" alt="SourceForge.net Logo" /></a>
+			</td>
+		</tr>
+	</table>
+</div>
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+</body>
+</html>
diff --git a/doc/doxygen.header.html b/doc/doxygen.header.html
new file mode 100644
index 0000000..97a03b9
--- /dev/null
+++ b/doc/doxygen.header.html
@@ -0,0 +1,7 @@
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
diff --git a/doc/html/Makefile.am b/doc/html/Makefile.am
new file mode 100644
index 0000000..2c73fdb
--- /dev/null
+++ b/doc/html/Makefile.am
@@ -0,0 +1,53 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = images
+
+html_DATA = \
+	changelog.html \
+	developers.html \
+	documentation.html \
+	documentation_bugs.html \
+	documentation_example_code.html \
+	documentation_format_overview.html \
+	documentation_tools.html \
+	documentation_tools_flac.html \
+	documentation_tools_metaflac.html \
+	faq.html \
+	favicon.ico \
+	features.html \
+	flac.css \
+	format.html \
+	id.html \
+	index.html \
+	license.html \
+	ogg_mapping.html
+
+EXTRA_DIST = $(html_DATA) api
+
+if FLaC__HAS_DOXYGEN
+# The install targets don't copy whole directories so we have to
+# handle 'api/' specially:
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(htmldir)/api
+	(cd $(builddir)/api && $(INSTALL_DATA) * $(DESTDIR)$(htmldir)/api)
+uninstall-local:
+	rm -rf $(DESTDIR)$(htmldir)/api
+distclean-local:
+	-rm -rf api
+endif
diff --git a/doc/html/changelog.html b/doc/html/changelog.html
new file mode 100644
index 0000000..fc0dc4d
--- /dev/null
+++ b/doc/html/changelog.html
@@ -0,0 +1,1560 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2004-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - changelog</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;changelog&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		changelog
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		This is an informal changelog, a summary of changes in each release.  (See also <a href="documentation_bugs.html">known bugs</a>.)  Particularly important for developers is the precise description of changes to the library interfaces.  See also the <a href="api/group__porting.html">porting guide</a> for specific instructions on porting to newer versions of FLAC.<br />
+
+		<a name="flac_1.3.3"><b>FLAC 1.3.3</b> (4-Augs-2019)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Fix CPU detection (Janne Hyvärinen).</li>
+					<li>Switch from unsigned types to uint32_t (erikd).</li>
+					<li>CppCheck fixes (erikd).</li>
+					<li>Improve SIMD decoding of 24 bit files (lvqcl).</li>
+					<li>POWER* amnd POWER9 improvements (Anton Blanchard).</li>
+					<li>More tests.</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>When converting to WAV, use WAVEFORMATEXTENSIBLE when bits per second is not 8 or 16 (erikd).</li>
+					<li>Fix --output-prefix with input-files in sub-directories (orbea).</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>Cmake support (Vitaliy Kirsanov, evpobr).</li>
+					<li>Visual Studio updates (Janne Hyvärinen).</li>
+					<li>Fix for MSVC when UNICODE is enabled (lvqcl).</li>
+					<li>Fix for OpenBSD/i386 (Christian Weisgerber).</li>
+				</ul>
+			</li>
+
+			<li>
+				documentation:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>(none).</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes:
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_3_2"><b>FLAC 1.3.2</b> (01-Jan-2017)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Fix undefined behaviour using GCC/Clang UBSAN (erikd).</li>
+					<li>General hardening via fuzz testing with AFL (erikd and others).</li>
+					<li>General code improvements (lvqcl, erikd and others).</li>
+					<li>Add FLAC in MP4 specification docs (Ralph Giles).</li>
+					<li>MSVS build cleanups (lvqcl).</li>
+					<li>Fix some cppcheck warnings (erikd).</li>
+					<li>Assume all currently used OSes support SSE2.</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>Fix potential infinite loop on flac-to-flac conversion (erikd).</li>
+					<li>Add  WAVEFORMATEXTENSIBLE to WAV (as needed) when decoding (lvqcl).</li>
+					<li>Only write vorbis-comments if they are non-empty.</li>
+					<li>Error out if decoding RAW with bits != (8|16|24).</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>Add --scan-replay-gain option.</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>Fixes for MSVC and Makefile.lite build systems.</li>
+				</ul>
+			</li>
+
+			<li>
+				documentation:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>CPU detection cleanup and fixes (Julian Calaby, erikd and lvqcl).</li>
+					<li>Fix two stream decoder bugs (Max Kellermann).</li>
+					<li>Fix a NULL dereference bug (on a malformed file).</li>
+					<li>Changed the LPC order guess for a slight compression improvement, particularly for classical music (Martijn van Beurden).</li>
+					<li>Improved encoding speed on older Intel CPUs.</li>
+					<li>Fixed a seeking bug when decoding certain files (Miroslav Lichvar).</li>
+					<li>Put an upper bound (32768) on the number of seek points.</li>
+					<li>Fix potential memory leaks.</li>
+					<li>Support 64bit brword/bwword allowing FLAC__BYTES_PER_WORD to be set to 8 (disabled by default).</li>
+					<li>Fix an out-of-bounds heap read.</li>
+					<li>Win32: Only use large buffers when writing to disk.</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes:
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_3_1"><b>FLAC 1.3.1</b> (25-Nov-2014)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Improved decoding efficiency of all bit depths but especially so for 24 bits for IA32 architecture (lvqcl and Miroslav Lichvar).</li>
+					<li>Faster encoding using SSE and AVX (lvqcl).</li>
+					<li>Fixed bartlett, bartlett_hann and triangle functions.</li>
+					<li>New apodization functions partial_tukey and punchout_tukey for improved compression (Martijn van Beurden).</li>
+					<li>Retuned compression presets to incorporate new apodization functions (Martijn van Beurden).</li>
+					<li>Fix -Wcast-align warnings on armhf architecture (Erik de Castro Lopo).</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>Help output documentation improvements.</li>
+					<li>I/O buffering improvements on Windows to reduce disk fragmentation when writing files.</li>
+					<li>Only write vorbis-comments if they are non-empty.</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>Fix symbol visibility in XMMS plugin.</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>Many fixes and improvements across all the build systems.</li>
+				</ul>
+			</li>
+
+			<li>
+				documentation:
+				<ul>
+					<li>Document new <a href="documentation_tools_flac.html#flac_options_apodization">apodization windows</a>.</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>Fix CVE-2014-9028 (heap write overflow) and CVE-2014-8962 (heap read overflow) (Erik de Castro Lopo).</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes:
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_3_0"><b>FLAC 1.3.0</b> (26-May-2013)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Move development to Xiph.org <a href="http://git.xiph.org/?p=flac.git;a=summary">git repository</a>.</li>
+					<li>The <span class="argument"><a href="documentation_tools_flac.html#flac_options_sector_align">--sector-align</a></span> option of <span class="commandname">flac</span> has been deprecated and may not exist in future versions.  <a href="http://www.etree.org/shnutils/shntool/">shntool</a> provides similar functionality.</li>
+					<li>Support for the RF64 and Wave64 formats in <span class="commandname">flac</span> (see below).</li>
+					<li>Better handling of cuesheets with non-CD-DA sample rates.</li>
+					<li>The <span class="argument"><a href="documentation_tools_flac.html#flac_options_ignore_chunk_sizes">--ignore-chunk-sizes</a></span> option has been added to the <span class="commandname">flac</span> command line tool.</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>Added support for encoding from and decoding to the RF64 format, and a new corresponding option <span class="argument"><a href="documentation_tools_flac.html#flac_options_force_rf64_format">--force-rf64-format</a></span>.  (<a href="http://sourceforge.net/p/flac/feature-requests/78/">SF #1762502</a>).  <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> is also supported.</li>
+					<li>Added support for encoding from and decoding to the Sony Wave64 format, and a new corresponding option <span class="argument"><a href="documentation_tools_flac.html#flac_options_force_wave64_format">--force-wave64-format</a></span>.  (<a href="http://sourceforge.net/p/flac/feature-requests/79/">SF #1769582</a>).  <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> is also supported.</li>
+					<li>Added new options <span class="argument"><a href="documentation_tools_flac.html#flac_options_preserve_modtime">--preserve-modtime</a></span> and <span class="argument"><a href="documentation_tools_flac.html#negative_options">--no-preserve-modtime</a></span> to specify whether or not output files should copy the timestamp and permissions from their input files.  The default is <span class="argument"><a href="documentation_tools_flac.html#flac_options_preserve_modtime">--preserve-modtime</a></span> as in previous versions.  (<a href="http://sourceforge.net/p/flac/feature-requests/85/">SF #1805428</a>).</li>
+					<li>Allow MM:SS:FF and MM:SS.SS time formats in non-CD-DA cuesheets.  (<a href="http://sourceforge.net/p/flac/feature-requests/95/">SF #1947353</a>, <a href="http://sourceforge.net/p/flac/bugs/338/">SF #2182432</a>)</li>
+					<li>The <span class="argument"><a href="documentation_tools_flac.html#flac_options_sector_align">--sector-align</a></span> option of <span class="commandname">flac</span> has been deprecated and may not exist in future versions.  <a href="http://www.etree.org/shnutils/shntool/">shntool</a> provides similar functionality. (<a href="http://sourceforge.net/p/flac/feature-requests/86/">SF #1805946</a>)</li>
+					<li>Improved error message when user attempts to decode a non-FLAC file (<a href="http://sourceforge.net/p/flac/bugs/341/">SF #2222789</a>).</li>
+					<li>Fix bug where <span class="commandname">flac</span> was disallowing use of <span class="argument">--replay-gain</span> when encoding from stdin (<a href="http://sourceforge.net/p/flac/bugs/313/">SF #1840124</a>).</li>
+					<li>Fix bug with fractional seconds on some locales (<a href="http://sourceforge.net/p/flac/bugs/309/">SF #1815517</a>, <a href="http://sourceforge.net/p/flac/bugs/321/">SF #1858012</a>).</li>
+					<li>Read and write appropriate channel masks for 6.1 and 7.1 surround input WAV files. Documentation was also updated.</li>
+					<li>Correct Wave64 GUIDs.</li>
+					<li>Support 56kHz to 192kHz gain analysis (patch from Earl Chew)</li>
+					<li>Add ability to handle unicode filenames on Windows (large set of patches from Janne Hyv&auml;rinen)</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>Allow MM:SS:FF and MM:SS.SS time formats in non-CD-DA cuesheets.  (<a href="http://sourceforge.net/p/flac/feature-requests/95/">SF #1947353</a>, <a href="http://sourceforge.net/p/flac/bugs/338/">SF #2182432</a>)</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>Minor updates for XMMS plugin.</li>
+					<li>Winamp2 plugin was dropped because Nullsoft has provided native FLAC support since 2006.</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>Fixes for autotools (including <a href="http://sourceforge.net/p/flac/patches/28/">SF #1859664</a>).</li>
+					<li>Fixes for MinGW (including <a href="http://sourceforge.net/p/flac/bugs/">SF #2000973</a>, <a href="http://sourceforge.net/p/flac/bugs/">SF #2209829</a>).</li>
+					<li>Fixes for gcc (including <a href="http://sourceforge.net/p/flac/bugs/">SF #1834168</a>, <a href="http://sourceforge.net/p/flac/bugs/334/">SF #2002481</a>).</li>
+					<li>Fixes for Sun Studio/Forte (<a href="http://sourceforge.net/p/flac/patches/22/">SF #1701960</a>).</li>
+					<li>Fixes for windows builds (including <a href="http://sourceforge.net/p/flac/bugs/257/">SF #1676822</a>, <a href="http://sourceforge.net/p/flac/feature-requests/73/">SF #1756624</a>, <a href="http://sourceforge.net/p/flac/bugs/307/">SF #1809863</a>, <a href="http://sourceforge.net/p/flac/feature-requests/">SF #1911149</a>).</li>
+					<li>Fixes for FreeBSD and OpenBSD.</li>
+					<li>Compile with GNU gcc _FORTIFY_SOURCE=2 and stack protection where those features are detected.</li>
+					<li>Enable a bunch of GCC compiler warnings and fix code that generates warnings.</li>
+				</ul>
+			</li>
+
+			<li>
+				documentation:
+				<ul>
+					<li>Document <span class="argument"><a href="documentation_tools_flac.html#flac_options_ignore_chunk_sizes">--ignore-chunk-sizes</a></span>
+						and <span class="argument"><a href="documentation_tools_flac.html#flac_options_apply_replaygain_which_is_not_lossless">--apply-replaygain-which-is-not-lossless</a></span>
+						option for <span class="commandname">flac</span>.</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>libFLAC encoder was defaulting to level 0 compression instead of 5 (<a href="http://sourceforge.net/p/flac/bugs/310/">SF #1816825</a>).</li>
+					<li>Fix bug in bitreader handling of read callback returning a short count (<a href="http://sourceforge.net/p/flac/bugs/345/">SF #2490454</a>).</li>
+					<li>Improve decoder's ability to distinguish between a FLAC sync code and an MPEG one (<a href="http://sourceforge.net/p/flac/bugs/346/">SF #2491433</a>).</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes:
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li><b>Added</b> FLAC__format_blocksize_is_subset()</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li>Add a number of convenience methods.</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_2_1"><b>FLAC 1.2.1</b> (17-Sep-2007)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>With the new <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> in <span class="commandname">flac</span>, non-audio RIFF and AIFF chunks can be stored in FLAC files and recreated when decoding.  This allows, among other, things support for archiving BWF files and other WAVE files from editing tools that preserves all the metadata. </li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>Specified 2 new APPLICATION metadata blocks for storing WAVE and AIFF chunks (for use with <a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a> in <span class="commandname">flac</span>).</li>
+					<li>The lead-out track number for non-CDDA cuesheets now must be 255.</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>This is not a format change, but changed default extension for Ogg FLAC from .ogg to .oga, according to new Xiph <a href="http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions">specification</a> (<a href="http://sourceforge.net/p/flac/bugs/283/">SF #1762492</a>).</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_flac.html#flac_options_no_utf8_convert">--no-utf8-convert</a></span> which works like it does in <span class="commandname">metaflac</span> (<a href="http://sourceforge.net/p/flac/feature-requests/35/">SF #973740</a>).</li>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> which can save/restore RIFF and AIFF chunks to/from FLAC files (<a href="http://sourceforge.net/p/flac/feature-requests/9/">SF #363478</a>).</li>
+					<li>Changed default extension for Ogg FLAC from .ogg to .oga, according to new Xiph <a href="http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions">specification</a> (<a href="http://sourceforge.net/p/flac/bugs/283/">SF #1762492</a>).</li>
+					<li>Fixed bug where using <span class="argument">--replay-gain</span> without any padding option caused only a small PADDING block to be created (<a href="http://sourceforge.net/p/flac/bugs/282/">SF #1760790</a>).</li>
+					<li>Fixed bug where encoding from stdin on Windows could fail if WAVE/AIFF contained unknown chunks (<a href="http://sourceforge.net/p/flac/bugs/290/">SF #1776803</a>).</li>
+					<li>Fixed bug where importing non-CDDA cuesheets would cause an invalid lead-out track number (<a href="http://sourceforge.net/p/flac/bugs/286/">SF #1764105</a>).</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>Changed default extension for Ogg FLAC from .ogg to .oga, according to new Xiph <a href="http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions">specification</a> (<a href="http://sourceforge.net/p/flac/bugs/283/">SF #1762492</a>).</li>
+					<li>Fixed bug where importing non-CDDA cuesheets would cause an invalid lead-out track number (<a href="http://sourceforge.net/p/flac/bugs/286/">SF #1764105</a>).</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>New configure option <span class="argument">--disable-cpplibs</span> to prevent building libFLAC++ (<a href="http://sourceforge.net/p/flac/patches/23/">SF #1723295</a>).</li>
+					<li>Fixed bug compiling <span class="commandname">flac</span> without Ogg support (<a href="http://sourceforge.net/p/flac/bugs/281/">SF #1760786</a>).</li>
+					<li>Fixed bug where sometimes an existing installation of flac could interfere with the build process (<a href="http://sourceforge.net/p/flac/bugs/285/">SF #1763690</a>).</li>
+					<li>OS X fixes (<a href="http://sourceforge.net/p/flac/patches/25/">SF #1786225</a>).</li>
+					<li>MinGW fixes (<a href="http://sourceforge.net/p/flac/bugs/264/">SF #1684879</a>).</li>
+					<li>Solaris 10 fixes (<a href="http://sourceforge.net/p/flac/bugs/294/">SF #1783225</a> <a href="http://sourceforge.net/p/flac/bugs/295/">SF #1783630</a>).</li>
+					<li>OS/2 fixes (<a href="http://sourceforge.net/p/flac/bugs/287/">SF #1771378</a> <a href="http://sourceforge.net/p/flac/bugs/174/">SF #1229495</a>).</li>
+					<li>automake-1.10 fixes (<a href="http://sourceforge.net/p/flac/bugs/300/">SF #1791361</a> <a href="http://sourceforge.net/p/flac/bugs/302/">SF #1792179</a>).</li>
+				</ul>
+			</li>
+			<li>
+				documentation:
+				<ul>
+					<li>Added new <a href="documentation_tools_flac.html#tutorial">tutorial</a> section for <span class="commandname">flac</span>.</li>
+					<li>Added <a href="documentation_example_code.html">example code</a> section for using libFLAC/libFLAC++.</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>libFLAC: Fixed very rare seek bug (<a href="http://sourceforge.net/p/flac/bugs/263/">SF #1684049</a>).</li>
+					<li>libFLAC: Fixed seek bug with Ogg FLAC and small streams (<a href="http://sourceforge.net/p/flac/bugs/301/">SF #1792172</a>).</li>
+					<li>libFLAC: 64-bit fixes (<a href="http://sourceforge.net/p/flac/bugs/299/">SF #1790872</a>).</li>
+					<li>libFLAC: Fix assembler code to be position independent.</li>
+					<li>libFLAC: Optimization of a number of inner loop functions.</li>
+					<li>Added support for encoding the residual coding method introduced in libFLAC 1.2.0 (RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) which will  encode 24-bit files more efficiently.</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes:
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li><b>Added</b> FLAC__metadata_simple_iterator_is_last()</li>
+							<li><b>Added</b> FLAC__metadata_simple_iterator_get_block_offset()</li>
+							<li><b>Added</b> FLAC__metadata_simple_iterator_get_block_length()</li>
+							<li><b>Added</b> FLAC__metadata_simple_iterator_get_application_id()</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li><b>Added</b> FLAC::Metadata::SimpleIterator::is_last()</li>
+							<li><b>Added</b> FLAC::Metadata::SimpleIterator::get_block_offset()</li>
+							<li><b>Added</b> FLAC::Metadata::SimpleIterator::get_block_length()</li>
+							<li><b>Added</b> FLAC::Metadata::SimpleIterator::get_application_id()</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_2_0"><b>FLAC 1.2.0</b> (23-Jul-2007)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Small encoding speedups for all modes.</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>One of the reserved bits in the FLAC frame header has been assigned for future use; make sure to refer to the <a href="api/group__porting__1__1__4__to__1__2__0.html">porting guide</a> if you parse FLAC streams manually.</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>Added runtime detection of SSE OS support for most operating systems.</li>
+					<li>Added a new undocumented option <span class="argument">--ignore-chunk-sizes</span> for ignoring the size of the 'data' chunk (WAVE) or 'SSND' chunk (AIFF).  Can be used to encode files with bogus data sizes (e.g. with WAV files piped from foobar2000 to flac.exe as an external encoder).  <b>Use with caution</b>: all subsequent data is treated as audio, so the data/SSND chunk must be the last or the following data/tags will be treated as audio and encoded.</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>Added solution and project files for building with VC++ 2005.</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>Added runtime detection of SSE OS support for most operating systems.</li>
+					<li>Fixed bug where invalid seek tables could cause some seeks to fail.</li>
+					<li>Added support for decoding the new residual coding method (RESIDUAL_CODING_METHOD_PARTITIONED_RICE2).</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes (see also the <a href="api/group__porting__1__1__4__to__1__2__0.html">porting guide</a> for specific instructions on porting to FLAC 1.2.0):
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li><b>Added</b> FLAC__format_sample_rate_is_subset()</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li><b>Added</b> FLAC::Decoder::Stream::get_decode_position()</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_1_4"><b>FLAC 1.1.4</b> (13-Feb-2007)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Improved compression with no change to format or decrease in speed.</li>
+					<li>Encoding and decoding speedups for all modes.  Encoding at -8 is twice as fast.</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>Improved compression with no change to format or decrease in speed.</li>
+					<li>Encoding and decoding speedups for all modes.  Encoding at -8 is twice as fast.</li>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_flac.html#flac_options_warnings_as_errors">-w,--warnings-as-errors</a></span> for treating all warnings as errors.</li>
+					<li>Allow <span class="argument"><a href="documentation_tools_flac.html#flac_options_picture">--picture</a></span> option to take only a filename, and have all other attributes extracted from the file itself.</li>
+					<li>Fixed a bug that caused suboptimal default compression settings in some locales (<a href="http://sourceforge.net/p/flac/bugs/237/">SF #1608883</a>).</li>
+					<li>Fixed a bug where FLAC-to-FLAC transcoding of a corrupted FLAC file would truncate the transcoded file at the first error (<a href="http://sourceforge.net/p/flac/bugs/241/">SF #1615019</a>).</li>
+					<li>Fixed a bug where using <span class="argument"><a href="documentation_tools_flac.html#flac_options_decode_through_errors">-F</a></span> with FLAC-to-FLAC transcoding of a corrupted FLAC would have no effect (<a href="http://sourceforge.net/p/flac/bugs/242/">SF #1615391</a>).</li>
+					<li>Fixed a bug where new PICTURE metadata blocks specified with <span class="argument"><a href="documentation_tools_flac.html#flac_options_picture">--picture</a></span> would not be transferred during FLAC-to-FLAC transcoding (<a href="http://sourceforge.net/p/flac/bugs/246/">SF #1627993</a>).</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>Allow <span class="argument"><a href="documentation_tools_metaflac.html#metaflac_shorthand_import_picture_from">--import-picture-from</a></span> option to take only a filename, and have all other attributes extracted from the file itself.</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>Fixed a bug in the XMMS plugin where Ctrl-3 (file info) would cause a crash if the file did not exist (<a href="http://sourceforge.net/p/flac/patches/20/">SF #1634941</a>).</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>Fixed a makefile linkage bug with libogg (<a href="http://sourceforge.net/p/flac/bugs/239/">SF #1611414</a>).</li>
+					<li>Added pkg-config files for libFLAC and libFLAC++ (<a href="http://sourceforge.net/p/flac/patches/21/">SF #1647881</a>).</li>
+					<li>Added <span class="argument">--disable-ogg</span> option for building without Ogg support even if libogg is installed (<a href="http://sourceforge.net/p/flac/bugs/165/">SF #1196996</a>).</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>Completely rewritten bitbuffer which uses native machine word size instead of bytes for dramatic speed improvements.  The speedup should be most dramatic on CPUs with slower byte manipulation capability and big-endian machines.</li>
+					<li>Much faster Rice partition size estimation which greatly speeds encoding in higher modes.</li>
+					<li>Increased compression for all modes.</li>
+					<li>Reduced memory requirements for encoder and decoder.</li>
+					<li>Fixed a bug with default apodization settings that were erroneous in some locales (<a href="http://sourceforge.net/p/flac/bugs/237/">SF #1608883</a>).</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes:
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li>(behavior only) FLAC__stream_encoder_set_metadata() now makes a copy of the "metadata" array of pointers (but still not copies of the objects themselves) so the client does not need to maintain its copy of the array after the call.</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_1_3"><b>FLAC 1.1.3</b> (27-Nov-2006)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Improved compression with no impact on format or decoding speed.</li>
+					<li>Much better recovery for corrupted files</li>
+					<li>Better multichannel support</li>
+					<li>Large file (&gt;2GB) support everywhere</li>
+					<li><span class="commandname">flac</span> now supports FLAC and Ogg FLAC as input to the encoder (e.g. can re-encode FLAC to FLAC) and preserve all the metadata like tags, etc.</li>
+					<li>New <span class="code"><a href="format.html#def_PICTURE">PICTURE</a></span> metadata block for storing things like cover art, new <span class="argument"><a href="documentation_tools_flac.html#flac_options_picture">--picture</a></span> option to <span class="commandname">flac</span> and <span class="argument"><a href="documentation_tools_metaflac.html#metaflac_shorthand_import_picture_from">--import-picture-from</a></span> option to <span class="commandname">metaflac</span> for importing pictures, new <span class="argument"><a href="documentation_tools_metaflac.html#metaflac_shorthand_export_picture_to">--export-picture-to</a></span> option to <span class="commandname">metaflac</span> for exporting pictures, and metadata API <a href="api/group__flac__metadata__level0.html#ga3">additions</a> for searching for suitable pictures based on type, size and color constraints.</li>
+					<li>Support for new <tt>REPLAYGAIN_REFERENCE_LOUDNESS</tt> tag.</li>
+					<li>Fixed a bug in Ogg FLAC encoding where metadata was not being updated properly.  Existing Ogg FLAC files should be recoded to fix up the metadata, e.g. <span class="command">flac -Vf -S 10s --ogg file.ogg</span></li>
+					<li>In the developer libraries, the interface has been simplfied by merging the three decoding layers into a single class; ditto for the encoders.  Also, libOggFLAC has been merged into libFLAC and libOggFLAC++ has been merged into libFLAC++ so there is a single API supporting both native FLAC and Ogg FLAC.</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>New <span class="code"><a href="format.html#def_PICTURE">PICTURE</a></span> metadata block for storing things like cover art.</li>
+					<li>Speaker assignments and channel orders for 3-6 channels (see <a href="format.html#frame_header">frame header</a>).</li>
+					<li>Further restrictions on the <a href="format.html#subset">FLAC subset</a> when the sample rate is &lt;=48kHz; in this case the maximum LPC order is now 12 and maximum blocksize is 4608.  This is to further limit the processing and memory requirements for hardware implementations while not measurably affecting compression.</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>Improved the <span class="argument"><a href="documentation_tools_flac.html#flac_options_decode_through_errors">-F</a></span> option to allow decoding of FLAC files whose metadata is corrupted, and other kinds of severe corruption.</li>
+					<li>Encoder can now take FLAC and Ogg FLAC as input.  The output FLAC file will have all the same metadata as the original unless overridden with options on the command line.</li>
+					<li>Encoder can now take WAVEFORMATEXTENSIBLE WAVE files as input; decoder will output WAVEFORMATEXTENSIBLE WAVE files when necessary to conform to the latest Microsoft specifications.</li>
+					<li>Now properly supports AIFF and WAVEFORMATEXTENSIBLE multichannel input, performing necessary channel reordering both for encoding and decoding.  WAVEFORMATEXTENSIBLE channel mask is also saved to a tag on encoding and restored on decoding for situations when there is no natural mapping to FLAC channel assignments.</li>
+					<li>Expanded support for "odd" sample resolutions to WAVE and AIFF input; all resolutions from 4 to 24 bits-per-sample now supported for all input types.</li>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_flac.html#flac_options_tag_from_file">--tag-from-file</a></span> for setting a tag from file (e.g. for importing a cuesheet as a tag).</li>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_flac.html#flac_options_picture">--picture</a></span> for adding pictures.</li>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_flac.html#flac_options_apodization">--apodization</a></span> for specifying the window function(s) to be used in LPC analysis.</li>
+					<li>Added support for encoding from non-compressed AIFF-C (<a href="http://sourceforge.net/p/flac/bugs/143/">SF #1090933</a>).</li>
+					<li>Importing of non-CDDA-compliant cuesheets now only issues a warning, not an error (see <a href="http://www.hydrogenaud.io/forums/index.php?showtopic=31282">here</a>).</li>
+					<li>MD5 comparison failures on decoding are now an error instead of a warning and will also return a non-zero exit code (<a href="http://sourceforge.net/p/flac/bugs/221/">SF #1493725</a>).</li>
+					<li>The default padding size is now 8K, or 64K if the input audio stream is more than 20 minutes long.</li>
+					<li>Fixed a bug in cuesheet parsing where it would return an error if the last line of the cuesheet did not end with a newline.</li>
+					<li>Fixed a bug that caused a crash when <span class="argument">-a</span> and <span class="argument">-t</span> were used together (<a href="http://sourceforge.net/p/flac/bugs/173/">SF #1229481</a>).</li>
+					<li>Fixed a bug with --sector-align where appended samples were not always totally silent (<a href="http://sourceforge.net/p/flac/bugs/179/">SF #1237707</a>).</li>
+					<li>Fixed bugs with --sector-align and raw input files.</li>
+					<li>Fixed a bug printing out unknown AIFF subchunk names (<a href="http://sourceforge.net/p/flac/bugs/186/">SF #1267476</a>).</li>
+					<li>Fixed a bug where WAVE files with "data" subchunks of size 0 where accepted (<a href="http://sourceforge.net/p/flac/bugs/190/">SF #1293830</a>).</li>
+					<li>Fixed a bug where sync error at end-of-stream of truncated files was not being caught (<a href="http://sourceforge.net/p/flac/bugs/183/">SF #1244071</a>).</li>
+					<li>Fixed a problem with filename parsing if file does not have extension but also has a . in the path (<a href="http://sourceforge.net/p/flac/bugs/159/">SF #1161916</a>).</li>
+					<li>Fixed a problem with fractional-second parsing for <span class="argument">--skip</span>/<span class="argument">--until</span> in some locales (<a href="http://sourceforge.net/p/flac/bugs/125/">SF #1031043</a>).</li>
+					<li>Increase progress report rate when -p and -e are used together (<a href="http://sourceforge.net/p/flac/bugs/229/">SF #1580122</a>).</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>Added support for read-only operations on Ogg FLAC files.</li>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_metaflac.html#metaflac_shorthand_set_tag_from_file">--set-tag-from-file</a></span> for setting a tag from file (e.g. for importing a cuesheet as a tag).</li>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_metaflac.html#metaflac_shorthand_import_picture_from">--import-picture-from</a></span> for importing pictures.</li>
+					<li>Added a new option <span class="argument"><a href="documentation_tools_metaflac.html#metaflac_shorthand_export_picture_to">--export-picture-to</a></span> for exporting pictures.</li>
+					<li>Added shorthand operation <span class="argument"><a href="documentation_tools_metaflac.html#metaflac_shorthand_remove_replay_gain">--remove-replay-gain</a></span> for removing ReplayGain tags.</li>
+					<li><span class="argument"><a href="documentation_tools_metaflac.html#metaflac_shorthand_export_cuesheet_to">--export-cuesheet-to</a></span> now properly specifies the FLAC file name (<a href="http://sourceforge.net/p/flac/feature-requests/46/">SF #1272825</a>).</li>
+					<li>Importing of non-CDDA-compliant cuesheets now issues a warning.</li>
+					<li>Removed the following deprecated tag editing options; you should use the new option names shown instead:
+						<ul>
+							<li>Removed <span class="argument">--show-vc-vendor</span>; use <span class="argument">--show-vendor-tag</span></li>
+							<li>Removed <span class="argument">--show-vc-field</span>; use <span class="argument">--show-tag</span></li>
+							<li>Removed <span class="argument">--remove-vc-all</span>; use <span class="argument">--remove-all-tags</span></li>
+							<li>Removed <span class="argument">--remove-vc-field</span>; use <span class="argument">--remove-tag</span></li>
+							<li>Removed <span class="argument">--remove-vc-firstfield</span>; use <span class="argument">--remove-first-tag</span></li>
+							<li>Removed <span class="argument">--set-vc-field</span>; use <span class="argument">--set-tag</span></li>
+							<li>Removed <span class="argument">--import-vc-from</span>; use <span class="argument">--import-tags-from</span></li>
+							<li>Removed <span class="argument">--export-vc-to</span>; use <span class="argument">--export-tags-to</span></li>
+						</ul>
+					</li>
+					<li>Disallow multiple input FLAC files when --import-tags-from=- is used (<a href="http://sourceforge.net/p/flac/bugs/141/">SF #1082577</a>).</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>When ReplayGain is on, if tags for the preferred kind of gain (album/track) are not in a stream, the other kind will be used.</li>
+					<li>Added ReplayGain info to file info box in XMMS plugin</li>
+					<li>Fixed UTF-8 decoder to disallow non-shortest-form and surrogate sequences (see <a href="http://www.unicode.org/versions/corrigendum1.html">here</a>).</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>Added support for building on OS/2 with EMX (<a href="http://sourceforge.net/p/flac/bugs/174/">SF #1229495</a>)</li>
+					<li>Added support for building with Borland C++ (<a href="http://sourceforge.net/p/flac/patches/17/">SF #1599018</a>)</li>
+					<li>Added a <span class="argument">--disable-xmms-plugin</span> option to <span class="command">configure</span> to prevent building the XMMS plugin (<a href="http://sourceforge.net/p/flac/feature-requests/33/">SF #930494</a>).</li>
+					<li>Added a <span class="argument">--disable-doxygen-docs</span> option to <span class="command">configure</span> for disabling Doxygen-based API doc generation (<a href="http://sourceforge.net/p/flac/patches/12/">SF #1365935</a>).</li>
+					<li>Added a <span class="argument">--disable-thorough-tests</span> option to <span class="command">configure</span> to do the basic library, stream, and tool tests in a reasonable time (<a href="http://sourceforge.net/p/flac/feature-requests/40/">SF #1077948</a>).</li>
+					<li>Added large file support with <span class="argument">AC_SYS_LARGEFILE</span>; use <span class="argument">--disable-largefile</span> with <span class="command">configure</span> to disable.</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>Merged libOggFLAC into libFLAC; both formats are now supported through the same API.</li>
+					<li>Merged libOggFLAC++ into libFLAC++; both formats are now supported through the same API.</li>
+					<li>libFLAC and libFLAC++: Simplified encoder setup with new <span class="argument">FLAC__stream_encoder_set_compression_level()</span> function.</li>
+					<li>libFLAC: Improved compression with no impact on FLAC format or decoding time by adding a windowing stage before LPC analysis.</li>
+					<li>libFLAC: Fixed a bug where missing STREAMINFO fields (min/max framesize, total samples, MD5 sum) and seek point offsets were not getting rewritten back to Ogg FLAC file (<a href="http://sourceforge.net/p/flac/bugs/197/">SF #1338969</a>).</li>
+					<li>libFLAC: Fixed a bug in cuesheet parsing where it would return an error if the last line of the cuesheet did not end with a newline.</li>
+					<li>libFLAC: Fixed UTF-8 decoder to disallow non-shortest-form and surrogate sequences (see <a href="http://www.unicode.org/versions/corrigendum1.html">here</a>).</li>
+					<li>libFLAC: Fixed a bug in the return value for <span class="argument">FLAC__stream_decoder_set_metadata_respond_application()</span> and <span class="argument">FLAC__stream_decoder_set_metadata_ignore_application()</span> when there was a memory allocation error (<a href="http://sourceforge.net/p/flac/bugs/176/">SF #1235005</a>).</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes (see also the <a href="api/group__porting__1__1__2__to__1__1__3.html">porting guide</a> for specific instructions on porting to FLAC 1.1.3):
+				<ul>
+					<li>
+						all libraries;
+						<ul>
+							<li>Merged libOggFLAC into libFLAC; both formats are now supported through the same API.</li>
+							<li>Merged libOggFLAC++ into libFLAC++; both formats are now supported through the same API.</li>
+							<li>Merged seekable stream decoder and file decoder into the stream decoder.</li>
+							<li>Merged seekable stream encoder and file encoder into the stream encoder.</li>
+							<li>Added #defines for the API version number to make porting easier; see <tt>include/lib*FLAC*/export.h</tt>.</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC:
+						<ul>
+							<li><b>Added</b> FLAC__stream_encoder_set_apodization()</li>
+							<li><b>Added</b> FLAC__stream_encoder_set_compression_level()</li>
+							<li><b>Added</b> FLAC__metadata_object_cuesheet_calculate_cddb_id()</li>
+							<li><b>Added</b> FLAC__metadata_get_cuesheet()</li>
+							<li><b>Added</b> FLAC__metadata_get_picture()</li>
+							<li><b>Added</b> FLAC__metadata_chain_read_ogg() and FLAC__metadata_chain_read_ogg_with_callbacks()</li>
+							<li><b>Changed</b> FLAC__stream_encoder_finish() now returns a FLAC__bool to signal a verify failure, or error processing last frame or updating metadata.</li>
+							<li><b>Changed</b> FLAC__StreamDecoderState: removed state FLAC__STREAM_DECODER_UNPARSEABLE_STREAM</li>
+							<li><b>Changed</b> FLAC__StreamDecoderErrorStatus: new error code FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM</li>
+							<li>The above two changes mean that when the decoder encounters what it thinks are unparseable frames from a future decoder, instead of returning a fatal error with the FLAC__STREAM_DECODER_UNPARSEABLE_STREAM state, it just calls the error callback with FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM and leaves the behavior up to the application.</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li><b>Added</b> FLAC::Metadata::Picture</li>
+							<li><b>Added</b> FLAC::Encoder::Stream::set_apodization()</li>
+							<li><b>Added</b> FLAC::Encoder::Stream::set_compression_level()</li>
+							<li><b>Added</b> FLAC::Metadata::CueSheet::calculate_cddb_id()</li>
+							<li><b>Added</b> FLAC::Metadata::get_cuesheet()</li>
+							<li><b>Added</b> FLAC::Metadata::get_picture()</li>
+							<li><b>Changed</b> FLAC::Metadata::Chain::read() to accept a flag denoting Ogg FLAC input</li>
+							<li><b>Changed</b> FLAC::Decoder::Stream::finish() now returns a bool to signal an MD5 failure like FLAC__stream_decoder_finish() does.</li>
+							<li><b>Changed</b> FLAC::Encoder::Stream::finish() now returns a bool to signal a verify failure, or error processing last frame or updating metadata.</li>
+						</ul>
+					</li>
+					<li>
+						libOggFLAC:
+						<ul>
+							<li>Merged into libFLAC.</li>
+						</ul>
+					</li>
+					<li>
+						libOggFLAC++:
+						<ul>
+							<li>Merged into libFLAC++.</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_1_2"><b>FLAC 1.1.2</b> (05-Feb-2005)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Sped up decoding by a few percent overall.</li>
+					<li>Sped up encoding when not using LPC (i.e. when using <span class="commandname">flac</span> options <span class="argument">-0</span>, <span class="argument">-1</span>, <span class="argument">-2</span>, or <span class="argument">-l 0</span>).</li>
+					<li>Fixed a decoding bug that could cause sync errors with some ID3v1-tagged FLAC files.</li>
+					<li>Added <a href="documentation_tools_metaflac.html#metaflac">HTML documentation for metaflac</a>.</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>New option <span class="argument"><a href="documentation_tools_flac.html#flac_options_input_size">--input-size</a></span> to manually specify the input size when encoding raw samples from stdin.</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>Added support for HTTP streaming in XMMS plugin.  <b>NOTE</b>: there is a bug in the XMMS mpg123 plugin that hijacks FLAC streams; to fix it you will need to add the '.flac' extension to the list of exceptions in <span class="code">Input/mpg123/mpg123.c:is_our_file()</span> in the XMMS sources and recompile.</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li>(none)</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>libFLAC: Sped up Rice block decoding in the bitbuffer, resulting in decoding speed gains of a few percent.</li>
+					<li>libFLAC: Sped up encoding when not using LPC (i.e. <span class="code">max_lpc_order == 0</span>).</li>
+					<li>libFLAC: Trailing NUL characters maintained on Vorbis comment entries so they can be treated like C strings.</li>
+					<li>libFLAC: More FLAC tag (i.e. Vorbis comment) validation.</li>
+					<li>libFLAC: Fixed a bug in the logic that determines the frame or sample number in a frame header; the bug could cause sync errors with some ID3v1-tagged FLAC files.</li>
+					<li>libFLAC, libOggFLAC: Can now be compiled to use only integer instructions, including encoding.  The decoder is almost completely integer anyway but there were a couple places that needed a fixed-point replacement.  There is no fixed-point version of LPC analysis yet, so if libFLAC is compiled integer-only, the encoder will behave as if the max LPC order is 0 (i.e. used fixed predictors only).  LPC decoding is supported in all cases as it always was integer-only.</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes:
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li><b>Changed:</b> Metadata object interface now maintains a trailing NUL on Vorbis comment entries for convenience.</li>
+							<li><b>Changed:</b> Metadata object interface now validates all Vorbis comment entries on input and returns false if an entry does not conform to the Vorbis comment spec.</li>
+							<li><b>Added</b> FLAC__format_vorbiscomment_entry_name_is_legal()</li>
+							<li><b>Added</b> FLAC__format_vorbiscomment_entry_value_is_legal()</li>
+							<li><b>Added</b> FLAC__format_vorbiscomment_entry_is_legal()</li>
+							<li><b>Added</b> FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair()</li>
+							<li><b>Added</b> FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair()</li>
+							<li><b>Changed</b> the signature of FLAC__metadata_object_vorbiscomment_entry_matches(): the first argument is now <span class="code">FLAC__StreamMetadata_VorbisComment_Entry entry</span> (was <span class="code">const FLAC__StreamMetadata_VorbisComment_Entry *entry</span>), i.e. <span class="code">entry</span> is now pass-by-value.</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li><b>Changed:</b> Metadata object interface now maintains a trailing NUL on Vorbis comment values for convenience.</li>
+							<li><b>Changed:</b> Metadata object interface now validates all Vorbis comment entries on input and returns false if an entry does not conform to the Vorbis comment spec.</li>
+							<li><b>Changed:</b> All Metadata objects' operator=() methods now return a reference to themselves.</li>
+							<li><b>Added</b> methods to FLAC::Metadata::VorbisComment::Entry for setting comment values from null-terminated strings:
+								<ul>
+									<li>Entry(const char *field)</li>
+									<li>Entry(const char *field_name, const char *field_value)</li>
+									<li>bool set_field(const char *field)</li>
+									<li>bool set_field_value(const char *field_value)</li>
+								</ul>
+							</li>
+							<li><b>Changed</b> the signature of FLAC::Metadata::VorbisComment::get_vendor_string() and FLAC::Metadata::VorbisComment::set_vendor_string() to use a UTF-8, NUL-terminated string <span class="code">const FLAC__byte *</span> for the vendor string instead of <span class="code">FLAC::Metadata::VorbisComment::Entry</span>.</li>
+							<li><b>Added</b> FLAC::Metadata::*::assign() to all Metadata objects.</li>
+							<li><b>Added</b> bool FLAC::Metadata::get_tags(const char *filename, VorbisComment &amp;tags)</li>
+						</ul>
+					</li>
+					<li>
+						libOggFLAC:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+					<li>
+						libOggFLAC++:
+						<ul>
+							<li>(none)</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_1_1"><b>FLAC 1.1.1</b> (01-Oct-2004)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>Ogg FLAC seeking now works</li>
+					<li>New optimizations almost double the decoding speed on PowerPC (e.g. Mac G4/G5)</li>
+					<li>A native OS X release thanks to updated Project Builder and autotools files</li>
+				</ul>
+			</li>
+			<li>
+				FLAC format:
+				<ul>
+					<li>Made invalid the metadata block type 127 so that audio frames can always be distinguished from metadata by seeing 0xff as the first byte.  (This was also required for the Ogg FLAC mapping.)</li>
+				</ul>
+			</li>
+			<li>
+				Ogg FLAC format:
+				<ul>
+					<li>First official FLAC-&gt;Ogg bitstream mapping standardized (see new <a href="ogg_mapping.html">FLAC-to-Ogg mapping specification</a>).  See the documentation for the <span class="argument"><a href="documentation_tools_flac.html#flac_options_ogg">--ogg</a></span> switch about having to re-encode older Ogg FLAC files.</li>
+				</ul>
+			</li>
+			<li>
+				flac:
+				<ul>
+					<li>Print an error when output file already exists instead of automatically overwriting.</li>
+					<li>New option <span class="argument"><a href="documentation_tools_flac.html#flac_options_force">-f</a></span> (<span class="argument"><a href="documentation_tools_flac.html#flac_options_force">--force</a></span>) to force overwriting if the output file already exists.</li>
+					<li>New option <span class="argument"><a href="documentation_tools_flac.html#flac_options_cue">--cue</a></span> to select a specific section to decode using cuesheet track/index points.</li>
+					<li>New option <span class="argument"><a href="documentation_tools_flac.html#flac_options_totally_silent">--totally-silent</a></span> to suppress all output.</li>
+					<li>New (but undocumented) option <span class="argument">--apply-replaygain-which-is-not-lossless</span> which applies ReplayGain to the decoded output.  See <a href="http://www.hydrogenaud.io/forums/index.php?showtopic=17293&amp;st=11">this thread</a> for usage and caveats.</li>
+					<li>When encoding to Ogg FLAC, use a random serial number (instead of 0 as was done before) when a serial number is not specified.</li>
+					<li>When encoding multiple Ogg FLAC streams, <span class="argument">--serial-number</span> or random serial number sets the first number, which is then incremented for subsequent streams (before, the same serial number was used for all streams).</li>
+					<li>Decoder no longer exits with an error when writing to stdout and the pipe is broken.</li>
+					<li>Better explanation of common error messages.</li>
+					<li>Default extension when writing AIFF files is .aif (before, it was .aiff).</li>
+					<li>Write more common representation of SANE numbers in AIFF files.</li>
+					<li>Bug fix: calculating ReplayGain on 48kHz streams.</li>
+					<li>Bug fix: check for supported block alignments in WAVE files.</li>
+					<li>Bug fix: "offset" field in AIFF SSND chunk properly handled.</li>
+					<li>Bug fix: <a href="http://sourceforge.net/p/flac/bugs/77/">#679166</a>: flac doesn't respect RIFF subchunk padding byte.</li>
+					<li>Bug fix: <a href="http://sourceforge.net/p/flac/bugs/90/">#828391</a>: --add-replay-gain segfaults.</li>
+					<li>Bug fix: <a href="http://sourceforge.net/p/flac/bugs/96/">#851155</a>: Can't seek to position in flac file.</li>
+					<li>Bug fix: <a href="http://sourceforge.net/p/flac/bugs/97/">#851756</a>: flac --skip --until reads entire file.</li>
+					<li>Bug fix: <a href="http://sourceforge.net/p/flac/bugs/100/">#877122</a>: problem parsing cuesheet with CATALOG entry.</li>
+					<li>Bug fix: <a href="http://sourceforge.net/p/flac/bugs/104/">#896057</a>: parsing ISRC number from cuesheet.</li>
+				</ul>
+			</li>
+			<li>
+				metaflac:
+				<ul>
+					<li>Renamed the tag editing options as follows (the <span class="argument">...-vc-...</span> options still work but are deprecated):
+						<ul>
+							<li><span class="argument">--show-vc-vendor</span> becomes <span class="argument">--show-vendor-tag</span></li>
+							<li><span class="argument">--show-vc-field</span> becomes <span class="argument">--show-tag</span></li>
+							<li><span class="argument">--remove-vc-all</span> becomes <span class="argument">--remove-all-tags</span></li>
+							<li><span class="argument">--remove-vc-field</span> becomes <span class="argument">--remove-tag</span></li>
+							<li><span class="argument">--remove-vc-firstfield</span> becomes <span class="argument">--remove-first-tag</span></li>
+							<li><span class="argument">--set-vc-field</span> becomes <span class="argument">--set-tag</span></li>
+							<li><span class="argument">--import-vc-from</span> becomes <span class="argument">--import-tags-from</span></li>
+							<li><span class="argument">--export-vc-to</span> becomes <span class="argument">--export-tags-to</span></li>
+						</ul>
+					</li>
+					<li>Better explanation of common error messages.</li>
+					<li>Bug fix: calculating ReplayGain on 48kHz streams.</li>
+					<li>Bug fix: incorrect numbers when printing seek points.</li>
+				</ul>
+			</li>
+			<li>
+				plugins:
+				<ul>
+					<li>Speed optimization in ReplayGain synthesis.</li>
+					<li>Speed optimization in XMMS playback.</li>
+					<li>Support for big-endian architectures in XMMS plugin.</li>
+					<li>Removed support for ID3 tags.</li>
+					<li>Bug fix: make hard limiter default to off in XMMS plugin.</li>
+					<li>Bug fix: stream length calculation bug in XMMS plugin, debian bug #200435</li>
+					<li>Bug fix: small memory leak in XMMS plugin.</li>
+				</ul>
+			</li>
+			<li>
+				build system:
+				<ul>
+					<li><span class="code">ordinals.h</span> is now static, not a build-generated file anymore.</li>
+				</ul>
+			</li>
+			<li>
+				libraries:
+				<ul>
+					<li>libFLAC: PPC+Altivec optimizations of some decoder routines.</li>
+					<li>libFLAC: Make stream encoder encode the blocksize and sample rate in the frame header if at all possible (not in STREAMINFO), even if subset encoding was not requested.</li>
+					<li>libFLAC: Bug fix: fixed seek routine where infinite loop could happen when seeking past end of stream.</li>
+					<li>libFLAC, libFLAC++: added methods to skip single frames, useful for quickly finding frame boundaries (see interface changes below).</li>
+					<li>libOggFLAC, libOggFLAC++: New seekable-stream and file encoder and decoder APIs to match native FLAC APIs (see interface changes below).</li>
+				</ul>
+			</li>
+			<li>
+				Interface changes:
+				<ul>
+					<li>
+						libFLAC:
+						<ul>
+							<li><b>Added</b> FLAC__metadata_get_tags()</li>
+							<li><b>Added</b> callback-based versions of metadata editing functions:
+								<ul>
+									<li>FLAC__metadata_chain_read_with_callbacks()</li>
+									<li>FLAC__metadata_chain_write_with_callbacks()</li>
+									<li>FLAC__metadata_chain_write_with_callbacks_and_tempfile()</li>
+									<li>FLAC__metadata_chain_check_if_tempfile_needed()</li>
+								</ul>
+							</li>
+							<li><b>Added</b> decoder functions for skipping single frames, also useful for quickly finding frame boundaries:
+								<ul>
+									<li>FLAC__stream_decoder_skip_single_frame()</li>
+									<li>FLAC__seekable_stream_decoder_skip_single_frame()</li>
+									<li>FLAC__file_decoder_skip_single_frame()</li>
+								</ul>
+							</li>
+							<li><b>Added</b> new required tell callback on seekable stream encoder:
+								<ul>
+									<li>FLAC__SeekableStreamEncoderTellStatus and FLAC__SeekableStreamEncoderTellStatusString[]</li>
+									<li>FLAC__SeekableStreamEncoderTellCallback</li>
+									<li>FLAC__seekable_stream_encoder_set_tell_callback()</li>
+								</ul>
+							</li>
+							<li><b>Changed</b> FLAC__SeekableStreamEncoderState by adding FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR</li>
+							<li><b>Changed</b> Tell callback is now required to initialize seekable stream encoder</li>
+							<li><b>Deleted</b> erroneous and unimplemented FLAC__file_decoder_process_remaining_frames()</li>
+						</ul>
+					</li>
+					<li>
+						libFLAC++:
+						<ul>
+							<li><b>Added</b> FLAC::Metadata::get_tags()</li>
+							<li><b>Added</b> decoder functions for skipping single frames, also useful for quickly finding frame boundaries:
+								<ul>
+									<li>FLAC::Decoder::Stream::skip_single_frame()</li>
+									<li>FLAC::Decoder::SeekableStream::skip_single_frame()</li>
+									<li>FLAC::Decoder::File::skip_single_frame()</li>
+								</ul>
+							</li>
+							<li><b>Added</b> encoder functions for setting metadata:
+								<ul>
+									<li>FLAC::Encoder::Stream::set_metadata(FLAC::Metadata::Prototype **metadata, unsigned num_blocks)</li>
+									<li>FLAC::Encoder::SeekableStream::set_metadata(FLAC::Metadata::Prototype **metadata, unsigned num_blocks)</li>
+									<li>FLAC::Encoder::File::set_metadata(FLAC::Metadata::Prototype **metadata, unsigned num_blocks)</li>
+								</ul>
+							</li>
+							<li><b>Added</b> new required tell callback on seekable stream encoder:
+								<ul>
+									<li>pure virtual FLAC::Encoder::SeekableStream::tell_callback()</li>
+								</ul>
+							</li>
+							<li><b>Changed</b> Tell callback is now required to initialize seekable stream encoder</li>
+							<li><b>Deleted</b> the following methods:
+								<ul>
+									<li>FLAC::Decoder::Stream::State::resolved_as_cstring()</li>
+									<li>FLAC::Encoder::Stream::State::resolved_as_cstring()</li>
+								</ul>
+							</li>
+						</ul>
+					</li>
+					<li>
+						libOggFLAC:
+						<ul>
+							<li><b>Added</b> OggFLAC__SeekableStreamDecoder interface</li>
+							<li><b>Added</b> OggFLAC__FileDecoder interface</li>
+							<li><b>Added</b> OggFLAC__SeekableStreamEncoder interface</li>
+							<li><b>Added</b> OggFLAC__FileEncoder interface</li>
+							<li><b>Added</b> OggFLAC__stream_decoder_get_resolved_state_string()</li>
+							<li><b>Added</b> OggFLAC__stream_encoder_get_resolved_state_string()</li>
+							<li><b>Added</b> OggFLAC__stream_encoder_set_metadata_callback()</li>
+							<li><b>Changed</b> OggFLAC__StreamDecoderState by adding OggFLAC__STREAM_DECODER_END_OF_STREAM</li>
+						</ul>
+					</li>
+					<li>
+						libOggFLAC++:
+						<ul>
+							<li><b>Added</b> OggFLAC::Decoder::SeekableStream interface</li>
+							<li><b>Added</b> OggFLAC::Decoder::File interface</li>
+							<li><b>Added</b> OggFLAC::Encoder::SeekableStream interface</li>
+							<li><b>Added</b> OggFLAC::Encoder::File interface</li>
+							<li><b>Added</b> OggFLAC::Decoder::Stream::get_resolved_state_string()</li>
+							<li><b>Added</b> OggFLAC::Encoder::Stream::get_resolved_state_string()</li>
+							<li><b>Added</b> pure virtual OggFLAC::Encoder::Stream::metadata_callback()</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_1_0"><b>FLAC 1.1.0</b> (26-Jan-2003)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				General:
+				<ul>
+					<li>All code is now <a href="http://valgrind.org/">Valgrind</a>-clean!</li>
+					<li>New <a href="format.html#def_CUESHEET">CUESHEET</a> metadata block for storing CD TOC and index point information.  Now a CD can be completely backed up to a single FLAC file for archival.</li>
+					<li><a href="http://www.replaygain.org/">ReplayGain</a> support.</li>
+					<li>Better compression of 24-bit files.</li>
+					<li>More complete AIFF support.</li>
+					<li>3DNow! optimizations enabled by default.</li>
+					<li>Complete MSVC build system with .dsp projects for everything, which can build both static libs and DLLs, and in debug or release mode, all in the same source tree.</li>
+				</ul>
+				<span class="commandname">flac</span>:
+				<ul>
+					<li>Can now decode FLAC to AIFF; new <span class="argument">--force-aiff-format</span> option.</li>
+					<li>New <span class="argument">--cuesheet</span> option for reading and storing a cuesheet when encoding a whole CD.  Automatically creates seek points for track and index points unless <span class="argument">--no-cued-seekpoints</span> is used.</li>
+					<li>New <span class="argument">--replay-gain</span> option for calculating ReplayGain values and storing them as tags.</li>
+					<li>New <span class="argument">--until</span> option complements <span class="argument">--skip</span> to stop decoding at a specified point in the stream.</li>
+					<li><span class="argument">--skip</span> and <span class="argument">--until</span> now also accept mm:ss.ss format.</li>
+					<li>New <span class="argument">-S #s</span> flavor to specify seekpoints every '#' number of seconds.</li>
+					<li><span class="commandname">flac</span> now defaults to <span class="argument">-S 10s</span> instead of <span class="argument">-S 100x</span> for the seek table.</li>
+					<li><span class="commandname">flac</span> now adds a 4k PADDING block by default (turn off with <span class="argument">--no-padding</span>).</li>
+					<li>Fixed a bug with --skip and AIFF-to-FLAC encoding.</li>
+					<li>Fixed a bug where decoding a FLAC file whose total_samples==0 in the STREAMINFO would corrupt the WAVE header.</li>
+				</ul>
+				<span class="commandname">metaflac</span>:
+				<ul>
+					<li>New <span class="argument">--import-cuesheet-from</span> option for reading and storing a cuesheet to a FLAC-encoded CD.  Automatically creates seek points for track and index points unless <span class="argument">--no-cued-seekpoints</span> is used.</li>
+					<li>New <span class="argument">--export-cuesheet-to</span> option for writing a cuesheet from a FLAC file for use with CD authoring software.</li>
+					<li>New <span class="argument">--add-replay-gain</span> option for calculating ReplayGain values and storing them as tags.</li>
+					<li>New <span class="argument">--add-seekpoint</span> option to add seekpoints to an existing FLAC file.  Includes new <span class="argument">--add-seekpoint=#s</span> flavor to add seekpoints every '#' number of seconds.</li>
+				</ul>
+				XMMS plugin:
+				<ul>
+					<li>Configurable sample resolution conversion with dither.</li>
+					<li>ReplayGain support with customizable noise shaping, pre-amp, and optional hard limiter.</li>
+					<li>New Vorbis comment editor.</li>
+					<li>File info now works.</li>
+					<li>Bitrate now shows the smoothed instantaneous bitrate.</li>
+					<li>Uses the ARTIST tag if there is no PERFORMER tag.</li>
+				</ul>
+				Winamp2 plugin:
+				<ul>
+					<li>Configurable sample resolution conversion with dither.</li>
+					<li>ReplayGain support with customizable noise shaping, pre-amp, and optional hard limiter.</li>
+					<li>File info now works.</li>
+					<li>Uses the ARTIST tag if there is no PERFORMER tag.</li>
+				</ul>
+				Libraries (developers take note!):
+				<ul>
+					<li>All code and tests are instrumented for Valgrind.  All tests run Valgrind-clean, meaning no memory leaks or buffer over/under-runs.</li>
+					<li>Separate 64-bit datapath through the filter in <span class="commandname">libFLAC</span> for better compression of &gt;16 bps files.</li>
+					<li><span class="code">FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)</span> now sets the vendor string.</li>
+					<li>The documentation on the usage of <span class="code">FLAC::Iterator::get_block()</span> in <span class="commandname">libFLAC++</span> has an important correction.  If you use this class make sure to read <a href="api/group__flacpp__metadata__level2.html">this</a>.</li>
+				</ul>
+			</li>
+		</ul>
+		<br />
+
+		<a name="flac_1_0_4"><b>FLAC 1.0.4</b> (24-Sep-2002)</a>
+
+		<br />
+		<ul>
+			<li>
+				Plugins:
+				<ul>
+					<li>Support for Vorbis comments, ID3 v1 and v2 tags.</li>
+					<li>Configurable title formatting and charset conversion in XMMS plugin.</li>
+					<li>Support for 8- and 24-bit FLAC files.  There is a compile-time option for raw 24-bit output or 24bps-to-16bps linear dithering (the default).</li>
+				</ul>
+				<span class="commandname">flac</span>:
+				<ul>
+					<li>Improved option parser (now uses getopt).</li>
+					<li>AIFF input support (thanks to Brady Patterson).</li>
+					<li>Small decoder speedup.</li>
+					<li><span class="argument">--sector-align</span> now supported for raw input files.</li>
+					<li>New -T, --tag options for adding Vorbis comments while encoding.</li>
+					<li>New --serial-number option for use with --ogg.</li>
+					<li>Automatically writes vendor string in Vorbis comments.</li>
+					<li>Drastically reduced memory requirements.</li>
+					<li>Fixed bug where extra fmt/data chunks that were supposed to be skipped were not getting skipped.</li>
+					<li>Fixed bug in granulepos setting for Ogg FLAC streams.</li>
+					<li>Fixed memory leak when encoding multiple files with -V.</li>
+				</ul>
+				<span class="commandname">metaflac</span>:
+				<ul>
+					<li>UTF-8 support in Vorbis comments.</li>
+					<li>New --import-vc-from and --export-vc-to commands for importing/exporting Vorbis comments from/to a file.  For example, the following can be used to copy tags back and forth:<br />
+					        <span class="code">
+					        metaflac --export-vc-to=- --no-utf8-convert file.flac | vorbiscomment --raw -w file.ogg<br />
+					        vorbiscomment --raw -l file.ogg | metaflac --import-vc-from=- --no-utf8-convert file.flac<br />
+					        </span>
+					</li>
+					<li>Fixed <a href="http://sourceforge.net/p/flac/bugs/54/">bug #606796</a> where <span class="commandname">metaflac</span> was failing on read-only files.</li>
+				</ul>
+				Libraries:
+				<ul>
+					<li>All APIs now meticulously documented via Doxygen.  <a href="api/index.html">See here</a>.</li>
+					<li>New <span class="commandname">libOggFLAC</span> and <span class="commandname">libOggFLAC++</span> libraries.  These wrap around <span class="commandname">libFLAC</span> to provide encoding and decoding of Ogg FLAC streams, providing interfaces similar to the ones of the native FLAC libraries.  These are also documented via Doxygen.</li>
+					<li>New FLAC__SeekableStreamEncoder and FLAC__FileEncoder in <span class="commandname">libFLAC</span> simplify common encoding tasks.</li>
+					<li>New verify mode in all encoders.</li>
+					<li>FLAC__stream_encoder_finish() now resets the defaults just like the stream decoders.</li>
+					<li>Drastically reduced memory requirements of encoders and decoders.</li>
+					<li>Encoder now automatically writes vendor string in VORBIS_COMMENT block.</li>
+					<li>Encoding speedup of fixed predictors and MD5 speedup for 16bps mono/stereo signals on x86 (thanks to Miroslav Lichvar).</li>
+					<li>Fixed bug in metadata interface where a bps in STREAMINFO > 16 was incorrectly parsed.</li>
+					<li>Fixed bug where aborting stream decoder could cause infinite loop.</li>
+					<li>Behavior change: simplified decoder *_process() commands.</li>
+					<li>Behavior change: calling FLAC__stream_encoder_init() calls write callback once for "fLaC" signature and once for each metadata block.</li>
+					<li>Behavior change: deprecated do_escape_coding and rice_parameter_search_distance in encoder.</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_0_3"><b>FLAC 1.0.3</b> (03-Jul-2002)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				New features:
+				<ul>
+					<li>24-bit input support restored in <span class="commandname">flac</span>.</li>
+					<li>Decoder speedup in <span class="commandname">libFLAC</span>, which is directly passed on to the command-line decoder and plugins.</li>
+					<li>New <span class="argument">-F</span> option to <span class="commandname">flac</span> to continue decoding in spite of errors.</li>
+					<li>Correctly set granulepos in Ogg packets so seeking Ogg FLAC streams will be easier.</li>
+					<li>New <a href="format.html#metadata_block_vorbis_comment">VORBIS_COMMENT</a> metadata block for tagging with Vorbis-style comments.</li>
+					<li>Vastly improved <span class="commandname">metaflac</span>, now with many editing and tagging options.</li>
+					<li>Partial id3v1 support in Winamp plugins.</li>
+					<li>Updated Winamp 3 plugin.</li>
+					<li>Note: new semantics for -P option in <span class="commandname">flac</span>.</li>
+					<li>Note: removed -R option in <span class="commandname">flac</span>.</li>
+				</ul>
+				New library features:
+				<ul>
+					<li>Previously mentioned decoder speedup in <span class="commandname">libFLAC</span>.</li>
+					<li>New metadata interface to <span class="commandname">libFLAC</span> for manipulating metadata in FLAC files.</li>
+					<li>New <span class="commandname">libFLAC++</span> API, an object wrapper around <span class="commandname">libFLAC</span>.</li>
+					<li>New <a href="format.html#metadata_block_vorbis_comment">VORBIS_COMMENT</a> metadata block for tagging with Vorbis-style comments.</li>
+					<li>Customizable metadata filtering by type in decoders.</li>
+					<li>Stream encoder can take an arbitrary list of metadata blocks, instead of just one SEEKTABLE and/or PADDING block.</li>
+				</ul>
+				Bugs fixed:
+				<ul>
+					<li>Fixed bug with using pipes under Windows.</li>
+					<li>Fixed several bugs in the plugins and made them more robust in general.</li>
+					<li>Fixed bug in <span class="commandname">flac</span> where decoding to WAVE of a FLAC file with 0 for total_samples in the STREAMINFO block yielded a WAVE chunk of 0 size.</li>
+					<li>Fixed bug in Ogg packet numbering.</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_0_2"><b>FLAC 1.0.2</b> (03-Dec-2001)</a>
+
+		<br />
+		<ul>
+			<li>
+				This release is only to fix a bug that was causing some of the plugins to crash sporadically.  It can also affect <span class="commandname">libFLAC</span> users that reuse one file decoder instance for multiple files
+			</li>
+		</ul>
+		<br />
+
+		<a name="flac_1_0_1"><b>FLAC 1.0.1</b> (14-Nov-2001)</a>
+
+		<br />
+		<ul>
+			<li>
+				New features for users:
+				<ul>
+					<li>Support for Ogg-FLAC, i.e. <span class="commandname">flac</span> can now read and write FLAC streams using Ogg as the transport layer.</li>
+					<li>New Winamp 3 plugin based on the Wasabi Beta 1 SDK.</li>
+					<li>New utilities for adding FLAC support to the Monkey's Audio GUI (see <a href="documentation_tasks.html#monkey">how</a>).</li>
+					<li>Mac OS X support.  The download area now contains an OS X binary release.</li>
+					<li>Mingw32 support.</li>
+					<li>Better handling of MS-specific 'fmt' chunks in WAVE files.</li>
+				</ul>
+				New features for developers:
+				<ul>
+					<li>Added a SeekableStreamDecoder layer between StreamDecoder and FileDecoder.  This makes it easier to use libFLAC in situations where files have been abstracted away.  See the latest <a href="api/index.html">documentation</a> for more.  The interface for the StreamDecoder and FileDecoder remain the same and are still binary-compatible with libFLAC 1.0.</li>
+					<li>Drastically reduced the stack requirements of the encoder.</li>
+				</ul>
+				Bug fixes:
+				<ul>
+					<li>Fixed a serious bug with <span class="commandname">flac</span> and raw input where the encoder was trying to rewind when it shouldn't, which would add 12 junk samples to the encoded file.  This was not present in WAVE encoding.</li>
+					<li>Fixed a minor bug in <span class="commandname">libFLAC</span> with setting the file name to stdin on a file decoder.</li>
+					<li>Fixed a minor bug in <span class="commandname">libFLAC</span> where multiple calls to setting the file name on a file decoder caused leaked memory.</li>
+					<li>Fixed a minor bug in <span class="commandname">metaflac</span>, now correctly skips an id3v2 tag if present.</li>
+					<li>Fixed a minor bug in <span class="commandname">metaflac</span>, now correctly skips long metadata blocks.</li>
+				</ul>
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_1_0"><b>FLAC 1.0</b> (20-Jul-2001)</a>
+
+		<br />
+		<ul>
+			<li>
+				It's finally here.  There are a few new features but mostly it is minor bug fixes since 0.10:
+				<ul>
+					<li>New '--sector-align' option to <span class="commandname">flac</span> which aligns a group of encoded files on CD audio sector boundaries.</li>
+					<li>New '--output-prefix' option to <span class="commandname">flac</span> to allow the user to prepend a prefix to all output filenames (useful, for example, for encoding/decoding to a different directory).</li>
+					<li>Better WAVE autodetection (doesn't rely on ungetc() anymore).</li>
+					<li>Cleaner one-line encoding/decoding stats.</li>
+					<li>Changes to the libFLAC interface and type names to make binary compatibility easier to maintain in the future.</li>
+					<li>New '--sse-os' option to 'configure' to enable faster SSE-based routines.</li>
+					<li>Another (hopefully last) fix to the Winamp 2 plugin.</li>
+					<li>Slightly improved Rice parameter estimation.</li>
+					<li>Bug fixes for some very rare corner cases when encoding.</li>
+				</ul>
+			</li>
+		</ul>
+		<br />
+
+		<a name="flac_0_10"><b>FLAC 0.10</b> (07-Jun-2001)</a>
+
+		<br />
+		<ul>
+			<li>
+				This is probably the final beta.  There have been many improvements in the last two months:
+				<ul>
+					<li>Both the encoder and decoder have been significantly sped up.  Aside from C improvements, the code base now has an assembly infrastructure that allows assembly routines for different architectures to be easily integrated.  Many key routines have now have faster IA-32 implementations (thanks to Miroslav).</li>
+					<li>A new metadata block <a href="format.html#def_SEEKTABLE">SEEKTABLE</a> has been defined to hold an arbitrary number of seek points, which speeds up seeking within a stream.</li>
+					<li><span class="commandname">flac</span> now has a command-line usage similar to 'gzip'; make sure to see the latest <a href="documentation.html">documentation</a> for the new usage.  It also attempts to preserve the input file's timestamp and permissions.</li>
+					<li>The -# options in <span class="commandname">flac</span> have been tweaked to yield the best compression-to-encode-time ratios.  The new default is -5.</li>
+					<li><span class="commandname">flac</span> can now usually autodetect WAVE files when encoding so that -fw is usually not needed when encoding from stdin.</li>
+					<li>The WAVE reader in <span class="commandname">flac</span> now just ignores (with a warning) unsupported sub-chunks instead of aborting with an error.</li>
+					<li>Added an option '--delete-input-file' to <span class="commandname">flac</span> which automatically deletes the input after a successful encode/decode.</li>
+					<li>Added an option '-o' to <span class="commandname">flac</span> to force the output file name (the old usage of "flac - outputfilename" is no longer supported).</li>
+					<li>Changed the XMMS plugin to send smaller chunks of samples (now 512) so that visualization is not slow.</li>
+					<li>Fixed a bug in the stream decoder where the decoded samples counter got corrupted after a seek.</li>
+				</ul>
+
+			</li>
+		</ul>
+		<br />
+
+		<a name="flac_0_9"><b>FLAC 0.9</b> (31-Mar-2001)</a>
+
+		<br />
+		<ul>
+			<li>
+				Bug fixes and some new features:
+				<ul>
+					<li>FLAC's sync code has been lengthened to 14 bits from 9 bits.  This should enable a faster and more robust synchronization mechanism.</li>
+					<li>Two reserved bits were added to the frame header.</li>
+					<li>A CRC-16 was added to the FLAC frame footer, and the decoder now does frame integrity checking based on the CRC.</li>
+					<li>The format now includes a new subframe field to indicate when a subblock has one or more 0 LSBs for all samples.  This increases compression on some kinds of data.</li>
+					<li>Added two options to the analysis mode, one for including the residual signal in the analysis file, and one for generating gnuplot files of each subframe's residual distribution with some statistics.  See the latest <a href="documentation.html#analysis_options">documentation</a>.</li>
+					<li>XMMS plugin now supports 8-bit files.</li>
+					<li>Fixed a bug in the Winamp2 plugin where the audio sounded garbled.</li>
+					<li>Fixed a bug in the Winamp2 plugin where Winamp would hang sporadically at the end of a track (c.f. <a href="http://sourceforge.net/projects/flac/&amp;atid=113478">bug #231197</a>).</li>
+				</ul>
+
+			</li>
+		</ul>
+
+		<br />
+
+		<a name="flac_0_8"><b>FLAC 0.8</b> (05-Mar-2001)</a>
+
+		<br />
+		<ul>
+			<li>
+				Changes since 0.7:
+				<ul>
+					<li>Created a new utility called <span class="commandname">metaflac</span>.  It is a metadata editor for .flac files.  Right now it just lists the contents of the metadata blocks but eventually it will allow update/insertion/deletion.</li>
+					<li>Added two new metadata blocks: PADDING which has an obvious function, and APPLICATION, which is meant to be open to third party applications.  See the <a href="format.html#def_APPLICATION">latest format docs</a> for more info, or the new <a href="id.html">id registration page</a>.</li>
+					<li>Added a <span class="argument">-P</span> option to <span class="commandname">flac</span> to reserve a PADDING block when encoding.</li>
+					<li>Added support for 24-bit files to <span class="commandname">flac</span> (the FLAC format always supported it).</li>
+					<li>Started the Winamp3 plugin.</li>
+					<li>Greatly expanded the test suite, adding more streams (24-bit streams, noise streams, non-audio streams, more patterns) and more option combinations to the encoder.  The test suite runs about 30 streams and over 5000 encodings now.</li>
+					<li>Fixed a bug in <span class="commandname">libFLAC</span> that happened when using an exhaustive LPC coefficient quantization search with 8 bps input.</li>
+					<li>Fixed a bug in <span class="commandname">libFLAC</span> where the error estimation in the fixed predictor could overflow.</li>
+					<li>Fixed a bug in <span class="commandname">libFLAC</span> where LPC was attempted even when the autocorrelation coefficients implied it wouldn't help.</li>
+					<li>Reworked the LPC coefficient quantizer, which also fixed another bug that might occur in rare cases.</li>
+					<li>Really fixed the '-V overflow' bug (c.f. <a href="http://sourceforge.net/p/flac/bugs/5/">bug #231976</a>).</li>
+					<li>Fixed a bug in <span class="commandname">flac</span> related to the decode buffer sizing.</li>
+				</ul>
+				FLAC is very close to being ready for an official release.  The only known problems left are with the Winamp plugins, which should be fixed soon, and pipes with MSVC.
+			</li>
+		</ul>
+		<br />
+
+		<a name="flac_0_7"><b>FLAC 0.7</b> (12-Feb-2001)</a>
+
+		<br />
+
+		<ul>
+			<li>
+				Changes:
+				<ul>
+					<li>Fixed a bug that happened when both -fr and --seek were used at the same time.</li>
+					<li>Fixed a bug with -p (c.f. <a href="http://sourceforge.net/p/flac/bugs/1/">bug #230992</a>).</li>
+					<li>Fixed a bug that happened when using large (&gt;32K) blocksizes and -V (c.f. <a href="http://sourceforge.net/p/flac/bugs/5/">bug #231976</a>).</li>
+					<li>Fixed a bug where encoder was double-closing a file.</li>
+					<li>Expanded the test suite.</li>
+					<li>Added more optimization flags for gcc, which should speed up flac.</li>
+				</ul>
+			</li>
+		</ul>
+		<br />
+
+		<a name="flac_0_6"><b>FLAC 0.6</b> (28-Jan-2001)</a>
+
+		<br />
+		<ul>
+			<li>
+				The encoder is now much faster.  The -m option has been sped up by 4x and -r improved, meaning that in the default compression mode (-6), encoding should be at least 3 times faster.  Other changes:
+				<ul>
+					<li>Some bugs related to <span class="commandname">flac</span> and pipes were fixed</li>
+					<li>A "loose mid-side" (<span class="argument">-M</span>) option to the encoder has been added, which adaptively switches between independent and mid-side coding, instead of the exhaustive search that <span class="argument">-m</span> does.</li>
+					<li>An analyze mode (<span class="argument">-a</span>) has been added to <span class="commandname">flac</span>.  This is useful mainly for developers; currently it will dump info about each frame and subframe to a file.  It's a text file in a format that can be easily processed by scripts; a separate analysis program is in the works.</li>
+					<li>The source now has an autoconf/libtool-based build system.  This should allow the source to build "out-of-the-box" on many more platforms.</li>
+				</ul>
+			</li>
+		</ul>
+		<br />
+
+		<a name="flac_0_5"><b>FLAC 0.5</b> (15-Jan-2001)</a>
+
+		<br />
+		<ul>
+			<li>
+				This is the first beta version of FLAC.  Being beta, there will be no changes to the format that will break older streams, unless a serious bug involving the format is found.  What this means is that, barring such a bug, streams created with 0.5 will be decodable by future versions.  This version also includes some new features:
+				<ul>
+					<li>An <a href="http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html">MD5 signature</a> of the unencoded audio is computed during encoding, and stored in the Encoding metadata block in the stream header.  When decoding, <span class="commandname">flac</span> will now compute the MD5 signature of the decoded data and compare it against the signature in the stream header.</li>
+					<li>A test mode (<span class="argument">-t</span>) has been added to <span class="commandname">flac</span>.  It works like decode mode but doesn't write an output file.</li>
+				</ul>
+			</li>
+		</ul>
+		<br />
+
+		<a name="flac_0_4"><b>FLAC 0.4</b> (23-Dec-2000)</a>
+
+		<br />
+		<ul>
+			<li>This version fixes a bug in the constant subframe detection.  More importantly, a verify option (-V) has been added to <span class="commandname">flac</span> that verifies the encoding process.  With this option turned on, <span class="commandname">flac</span> will create a parallel decoder while encoding to make sure that the encoded output decodes to exactly match the original input.  In this way, any unknown bug in the encoder will be caught and <span class="commandname">flac</span> will abort with an error message.</li>
+		</ul>
+
+
+
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2004-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/developers.html b/doc/html/developers.html
new file mode 100644
index 0000000..06d31c0
--- /dev/null
+++ b/doc/html/developers.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - developers</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;developers&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		developers
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		FLAC is an open source project and we are happy to enlist the help of anyone who wants to contribute, or to help with FLAC support in other programs and devices.  The preferred method of communication is the <a href="http://lists.xiph.org/mailman/listinfo/flac-dev">developer mailing list</a> (you must subscribe to post).<br />
+		<br />
+		FLAC is open to third-party developers who want to add support for FLAC into their programs.  All the necessary functionality is contained in the libFLAC libraries which are licensed under <a href="license.html">Xiph.org's BSD license</a>.<br />
+		<br />
+		Some pointers to developer documentation and code:<br />
+		<ul>
+			<li><a href="license.html">License</a> - The license under which the official tools are distributed.</li>
+			<li><a href="api/index.html">libFLAC and libFLAC++ APIs</a> - Complete library documentation.</li>
+			<li><a href="documentation_example_code.html">Example Code</a> - Some simple example programs demonstrating the use of libFLAC and libFLAC++.</li>
+			<li><a href="format.html">FLAC Format Specification</a> - The formal specification.</li>
+			<li><a href="ogg_mapping.html">Ogg FLAC Mapping</a> - How FLAC should be embedded in an Ogg container.</li>
+			<li><a href="id.html">ID Registration</a> - Register an ID if you need to write custom metadata.</li>
+			<li><a href="https://git.xiph.org/?p=flac.git;a%3Dsummary">Git access</a> - for checking out the source code.</li>
+			<li><a href="http://sourceforge.net/p/flac/bugs/">Bug Tracker</a> - to submit bug reports and patches</li>
+		</ul>
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+<br />
+
+<div class="box">
+	<div class="box_title">
+		goals
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		Since FLAC is an open-source project, it's important to have a set of goals that everyone works to.  They may change slightly from time to time but they're a good guideline.  Changes should be in line with the goals and should not attempt to embrace any of the anti-goals.<br />
+		<br />
+		<b>Goals</b>
+		<ul>
+			<li>
+				FLAC should be and stay an open format with an open-source reference implementation.
+			</li>
+			<li>
+				FLAC should be lossless.  This seems obvious but lossy compression seems to creep into every audio codec.  This goal also means that <span class="commandname">flac</span> should stay archival quality and be truly lossless for all input.  Testing of releases should be thorough.
+			</li>
+			<li>
+				FLAC should yield respectable compression, on par or better than other lossless codecs.
+			</li>
+			<li>
+				FLAC should allow at least realtime decoding on even modest hardware.
+			</li>
+			<li>
+				FLAC should support fast sample-accurate seeking.
+			</li>
+			<li>
+				FLAC should allow gapless playback of consecutive streams.  This follows from the lossless goal.
+			</li>
+			<li>
+				The FLAC project owes a lot to the many people who have advanced the audio compression field so freely, and aims also to contribute through the open-source development of new ideas.
+			</li>
+		</ul>
+		<b>Anti-goals</b><br />
+		<ul>
+			<li>
+				Lossy compression.  There are already many suitable lossy formats (<a href="http://www.xiph.org/vorbis/">Ogg Vorbis</a>, <a href="http://www.mp3-tech.org/">MP3</a>, etc.).
+			</li>
+			<li>
+				Copy prevention, DRM, etc.  There is no intention to add any copy prevention methods.  Of course, we can't stop someone from encrypting a FLAC stream in another container (e.g. the way Apple encrypts AAC in MP4 with FairPlay), that is the choice of the user.
+			</li>
+		</ul>
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/documentation.html b/doc/html/documentation.html
new file mode 100644
index 0000000..d245e84
--- /dev/null
+++ b/doc/html/documentation.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - documentation</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;documentation&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		documentation
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		FLAC is a general purpose audio format supported by many programs.  Most of the documentation here is about the FLAC format itself and the tools we provide, but there is also information on using other programs that support FLAC.
+		<ul>
+			<li><a href="features.html">Introduction</a> - What is FLAC?</li>
+			<li><a href="http://xiph.org/flac/download.html">Getting FLAC</a> - How to download what you need to play or make FLAC files.</li>
+			<li><a href="http://xiph.org/flac/documentation_tasks.html">Using FLAC</a> - If you have some FLAC files and want to do something with them, or want to create FLAC files, look here.</li>
+			<li><a href="faq.html">FAQ</a> - Frequently Asked Questions</li>
+		</ul>
+		In more detail:
+		<ul>
+			<li><a href="documentation_format_overview.html">About the FLAC Format</a> - An overview of the FLAC format for power users.</li>
+			<li><a href="documentation_tools.html">Official Tools</a> - How to use the <span class="commandname">flac</span> and <span class="commandname">metaflac</span> command-line tools.</li>
+			<li><a href="http://xiph.org/flac/comparison.html">Comparison</a> - A comparison of FLAC with other lossless codecs.</li>
+			<li><a href="documentation_bugs.html">Bugs</a> - How to report bugs and request features, and a list of known bugs in the FLAC tools.</li>
+			<li><a href="http://sourceforge.net/p/flac/support-requests/">Request Support</a> - Support for the official FLAC tools.  For other programs, use <a href="http://www.hydrogenaud.io/">hydrogenaud.io</a></li>
+			<li><a href="http://lists.xiph.org/mailman/listinfo/flac">FLAC Mailing List</a> - General discussion about FLAC, tools, releases, etc.  (You must subscribe to post.)</li>
+		</ul>
+		For developers who want to add FLAC support to their programs:
+		<ul>
+			<li><a href="documentation_format_overview.html">About the FLAC Format</a> - An overview of the FLAC format for power users.</li>
+			<li><a href="format.html">FLAC Format Specification</a> - The formal specification.</li>
+			<li><a href="ogg_mapping.html">Ogg FLAC Mapping</a> - How FLAC should be embedded in an Ogg container.</li>
+			<li><a href="api/index.html">libFLAC and libFLAC++ APIs</a> - Complete library documentation.</li>
+			<li><a href="documentation_example_code.html">Example Code</a> - Some simple example programs demonstrating the use of libFLAC and libFLAC++.</li>
+			<li><a href="license.html">License</a> - The license under which the official tools are distributed.</li>
+			<li>(see also the <a href="developers.html">developer page</a>)</li>
+		</ul>
+		Keep in mind that the online version of the documentation will always apply to the latest release.  For older releases, check the documentation included with the release package.
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/documentation_bugs.html b/doc/html/documentation_bugs.html
new file mode 100644
index 0000000..ad8b211
--- /dev/null
+++ b/doc/html/documentation_bugs.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - documentation</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		<a name="bugs">known bugs</a>
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		The following are major known bugs in the current (1.3.3) release:
+		<ul>
+			<li>
+				When encoding to Ogg FLAC, the number of seek points is limited to 240.
+			</li>
+		</ul>
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+<br />
+
+<div class="box">
+	<div class="box_title">
+		<a name="bug_reporting">reporting bugs</a>
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		To report a bug, please go to the <a href="http://sourceforge.net/p/flac/bugs/">FLAC bug tracker</a> (or appropriately the <a href="http://sourceforge.net/p/flac/feature-requests/">feature request tracker</a>, <a href="http://sourceforge.net/p/flac/patches/">patch page</a>, or <a href="http://sourceforge.net/p/flac/support-requests/">support page</a>).<br />
+		<br />
+		First check that there is not already an existing request.  If you do submit a new request, make sure and provide an email contact <b>and</b> use the Monitor feature.
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/documentation_example_code.html b/doc/html/documentation_example_code.html
new file mode 100644
index 0000000..dea608a
--- /dev/null
+++ b/doc/html/documentation_example_code.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - developers</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		example code
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		The FLAC source code has several small example programs that demonstrate how to use the libraries.  The source is available on the <a href="http://xiph.org/flac/download.html">download page</a>, or can be <a href="https://git.xiph.org/?p=flac.git">checked out from git</a>.  The examples complement the <a href="api/index.html">API documentation</a>.<br />
+		<br />
+		Currently the examples show how to encode WAV files to FLAC and vice-versa using both libFLAC and libFLAC++.  Over time we'll be adding more examples.
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/documentation_format_overview.html b/doc/html/documentation_format_overview.html
new file mode 100644
index 0000000..5710522
--- /dev/null
+++ b/doc/html/documentation_format_overview.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - documentation</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		<a name="format">format</a>
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		The basic structure of a FLAC stream is:
+		<ul>
+			<li>The four byte string "<span class="code">fLaC</span>"</li>
+			<li>The <a href="format.html#def_STREAMINFO"><span class="code">STREAMINFO</span></a> metadata block</li>
+			<li>Zero or more other metadata blocks</li>
+			<li>One or more audio frames</li>
+		</ul>
+		The first four bytes are to identify the FLAC stream.  The metadata that follows contains all the information about the stream except for the audio data itself.  After the metadata comes the encoded audio data.<br />
+		<br />
+		<b>METADATA</b><br />
+		<br />
+		FLAC defines several types of metadata blocks (see the <a href="format.html">format</a> page for the complete list).  Metadata blocks can be any length and new ones can be defined.  A decoder is allowed to skip any metadata types it does not understand.  Only one is mandatory: the <span class="code">STREAMINFO</span> block.  This block has information like the sample rate, number of channels, etc., and data that can help the decoder manage its buffers, like the minimum and maximum data rate and minimum and maximum block size.  Also included in the <span class="code">STREAMINFO</span> block is the MD5 signature of the <i>unencoded</i> audio data.  This is useful for checking an entire stream for transmission errors.<br />
+		<br />
+		Other blocks allow for padding, seek tables, tags, cuesheets, and application-specific data.  There are <a href="documentation_tools_flac.html"><span class="commandname">flac</span> options</a> for adding <span class="code">PADDING</span> blocks or specifying seek points.  FLAC does not require seek points for seeking but they can speed up seeks, or be used for cueing in editing applications.<br />
+		<br />
+		Also, if you have a need of a custom metadata block, you can define your own and request an ID <a href="id.html">here</a>.  Then you can reserve a <span class="code">PADDING</span> block of the correct size when encoding, and overwrite the padding block with your <span class="code">APPLICATION</span> block after encoding.  The resulting stream will be FLAC compatible; decoders that are aware of your metadata can use it and the rest will safely ignore it.<br />
+		<br />
+		<b>AUDIO DATA</b><br />
+		<br />
+		After the metadata comes the encoded audio data.  Audio data and metadata are not interleaved.  Like most audio codecs, FLAC splits the unencoded audio data into blocks, and encodes each block separately.  The encoded block is packed into a frame and appended to the stream.  The reference encoder uses a single block size for the whole stream but the FLAC format does not require it.<br />
+		<br />
+		<b>BLOCKING</b><br />
+		<br />
+		The block size is an important parameter to encoding.  If it is too small, the frame overhead will lower the compression.  If it is too large, the modeling stage of the compressor will not be able to generate an efficient model.  Understanding FLAC's modeling will help you to improve compression for some kinds of input by varying the block size.  In the most general case, using linear prediction on 44.1kHz audio, the optimal block size will be between 2-6 ksamples.  <span class="commandname">flac</span> defaults to a block size of 4096 in this case.  Using the fast fixed predictors, a smaller block size is usually preferable because of the smaller frame header.<br />
+		<br />
+		<b>INTER-CHANNEL DECORRELATION</b><br />
+		<br />
+		In the case of stereo input, once the data is blocked it is optionally passed through an inter-channel decorrelation stage.  The left and right channels are converted to center and side channels through the following transformation: mid = (left + right) / 2, side = left - right.  This is a lossless process, unlike joint stereo.  For normal CD audio this can result in significant extra compression.  <span class="commandname">flac</span> has two options for this: <span class="argument">-m</span> always compresses both the left-right and mid-side versions of the block and takes the smallest frame, and <span class="argument">-M</span>, which adaptively switches between left-right and mid-side.<br />
+		<br />
+		<b>MODELING</b><br />
+		<br />
+		In the next stage, the encoder tries to approximate the signal with a function in such a way that when the approximation is subtracted, the result (called the <i>residual</i>, <i>residue</i>, or <i>error</i>) requires fewer bits-per-sample to encode.  The function's parameters also have to be transmitted so they should not be so complex as to eat up the savings.  FLAC has two methods of forming approximations: 1) fitting a simple polynomial to the signal; and 2) general linear predictive coding (LPC).  I will not go into the details here, only some generalities that involve the encoding options.<br />
+		<br />
+		First, fixed polynomial prediction (specified with <span class="argument">-l 0</span>) is much faster, but less accurate than LPC.  The higher the maximum LPC order, the slower, but more accurate, the model will be.  However, there are diminishing returns with increasing orders.  Also, at some point (usually around order 9) the part of the encoder that guesses what is the best order to use will start to get it wrong and the compression will actually decrease slightly; at that point you will have to you will have to use the exhaustive search option <span class="argument">-e</span> to overcome this, which is significantly slower.<br />
+		<br />
+		Second, the parameters for the fixed predictors can be transmitted in 3 bits whereas the parameters for the LPC model depend on the bits-per-sample and LPC order.  This means the frame header length varies depending on the method and order you choose and can affect the optimal block size.<br />
+		<br />
+		<b>RESIDUAL CODING</b><br />
+		<br />
+		Once the model is generated, the encoder subracts the approximation from the original signal to get the residual (error) signal.  The error signal is then losslessly coded.  To do this, FLAC takes advantage of the fact that the error signal generally has a Laplacian (two-sided geometric) distribution, and that there are a set of special Huffman codes called Rice codes that can be used to efficiently encode these kind of signals quickly and without needing a dictionary.<br />
+		<br />
+		Rice coding involves finding a single parameter that matches a signal's distribution, then using that parameter to generate the codes.  As the distribution changes, the optimal parameter changes, so FLAC supports a method that allows the parameter to change as needed.  The residual can be broken into several <i>contexts</i> or <i>partitions</i>, each with it's own Rice parameter.  <span class="commandname">flac</span> allows you to specify how the partitioning is done with the <span class="argument">-r</span> option.  The residual can be broken into 2^<i>n</i> partitions, by using the option <span class="argument">-r n,n</span>.  The parameter <i>n</i> is called the <i>partition order</i>.  Furthermore, the encoder can be made to search through <i>m</i> to <i>n</i> partition orders, taking the best one, by specifying <span class="argument">-r m,n</span>.  Generally, the choice of n does not affect encoding speed but m,n does.  The larger the difference between m and n, the more time it will take the encoder to search for the best order.  The block size will also affect the optimal order.<br />
+		<br />
+		<b>FRAMING</b><br />
+		<br />
+		An audio frame is preceded by a frame header and trailed by a frame footer.  The header starts with a sync code, and contains the minimum information necessary for a decoder to play the stream, like sample rate, bits per sample, etc.  It also contains the block or sample number and an 8-bit CRC of the frame header.  The sync code, frame header CRC, and block/sample number allow resynchronization and seeking even in the absence of seek points.  The frame footer contains a 16-bit CRC of the entire encoded frame for error detection.  If the reference decoder detects a CRC error it will generate a silent block.<br />
+		<br />
+		<b>MISCELLANEOUS</b><br />
+		<br />
+		As a convenience, the reference decoder knows how to skip <a href="http://www.id3.org/">ID3v1 and ID3v2 tags</a>.  Note however that the FLAC specification does not require compliant implementations to support ID3 in any form and their use is strongly discouraged.<br />
+		<br />
+		<span class="commandname">flac</span> has a verify option <span class="argument">-V</span> that verifies the output while encoding.  With this option, a decoder is run in parallel to the encoder and its output is compared against the original input.  If a difference is found <span class="commandname">flac</span> will stop with an error.
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/documentation_tools.html b/doc/html/documentation_tools.html
new file mode 100644
index 0000000..971dfeb
--- /dev/null
+++ b/doc/html/documentation_tools.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - documentation</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		tools
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		FLAC is a general purpose audio format supported by many programs, but in this section we are concentrating on just the official tools provided by the FLAC project:
+		<ul>
+			<li><a href="documentation_tools_flac.html">flac</a> - The command-line encoder and decoder.</li>
+			<li><a href="documentation_tools_metaflac.html">metaflac</a> - The command-line metadata editor.</li>
+		</ul>
+		Other resources:
+		<ul>
+			<li><a href="documentation_bugs.html">Bugs</a> - How to report bugs and request features, and a list of known bugs in the FLAC tools.</li>
+			<li><a href="http://sourceforge.net/p/flac/support-requests/">Request Support</a> - Support for the official FLAC tools.  For other programs, use <a href="http://www.hydrogenaud.io/">hydrogenaud.io</a></li>
+			<li><a href="http://lists.xiph.org/mailman/listinfo/flac">FLAC Mailing List</a> - General discussion about FLAC, tools, releases, etc.  (You must subscribe to post.)</li>
+		</ul>
+		<br />
+		See <a href="http://xiph.org/flac/download.html">Getting FLAC</a> for instructions on downloading and installing the official FLAC tools, or <a href="http://xiph.org/flac/documentation_tasks.html">Using FLAC</a> for instructions and guides on playing FLAC files, ripping CDs to FLAC, etc.
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/documentation_tools_flac.html b/doc/html/documentation_tools_flac.html
new file mode 100644
index 0000000..8496aca
--- /dev/null
+++ b/doc/html/documentation_tools_flac.html
@@ -0,0 +1,1189 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - documentation</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		<a name="flac">flac</a>
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		<a name="toc"><font size="+1"><b><u>Table of Contents</u></b></font></a>
+		<ul>
+			<li><a href="#usage">General Usage</a></li>
+			<li><a href="#tutorial">Tutorial</a></li>
+			<li><a href="#general_options">General Options</a></li>
+			<li><a href="#analysis_options">Analysis Options</a></li>
+			<li><a href="#decoding_options">Decoding Options</a></li>
+			<li><a href="#encoding_options">Encoding Options</a></li>
+			<li><a href="#format_options">Format Options</a></li>
+			<li><a href="#negative_options">Negative Options</a></li>
+			<li><a href="#option_index">Option Index</a></li>
+		</ul>
+		<a name="usage"><font size="+1"><b><u>General Usage</u></b></font></a><br />
+		<br />
+		<span class="commandname">flac</span> is the command-line file encoder/decoder.  The encoder currently supports as input RIFF WAVE, Wave64, RF64, AIFF, FLAC or Ogg FLAC format, or raw interleaved samples.  The decoder currently can output to RIFF WAVE, Wave64, RF64, or AIFF format, or raw interleaved samples.  <span class="commandname">flac</span> only supports linear PCM samples (in other words, no A-LAW, uLAW, etc.), and the input must be between 4 and 24 bits per sample.  This is not a limitation of the FLAC format, just the reference encoder/decoder.<br />
+		<br />
+		<span class="commandname">flac</span> assumes that files ending in ".wav" or that have the RIFF WAVE header present are WAVE files, files ending in ".w64" or have the Wave64 header present are Wave64 files, files ending in ".rf64" or have the RF64 header present are RF64 files, files ending in ".aif" or ".aiff" or have the AIFF header present are AIFF files, and files ending in ".flac" or have the FLAC header present are FLAC files.  This assumption may be overridden with a command-line option.  It also assumes that files ending in ".oga" or ".ogg" or have the Ogg FLAC header present are Ogg FLAC files.  Other than this, <span class="commandname">flac</span> makes no assumptions about file extensions, though the convention is that FLAC files have the extension ".flac" (or ".fla" on ancient "8.3" file systems like FAT-16).<br />
+		<br />
+		Before going into the full command-line description, a few other things help to sort it out: 1) <span class="commandname">flac</span> encodes by default, so you must use <b>-d</b> to decode; 2) the options <span class="argument">-0</span> .. <span class="argument">-8</span> (or <span class="argument">--fast</span> and <span class="argument">--best</span>) that control the compression level actually are just synonyms for different groups of specific encoding options (described later) and you can get the same effect by using the same options; 3) <span class="commandname">flac</span> behaves similarly to gzip in the way it handles input and output files.<br />
+		<br />
+		Skip to the <a href="#tutorial">tutorial</a> below for examples of some common tasks.<br />
+		<br />
+		<span class="commandname">flac</span> will be invoked one of four ways, depending on whether you are encoding, decoding, testing, or analyzing:
+		<ul>
+			<li>
+				Encoding: flac [<i><a href="#general_options">&lt;general-options&gt;</a></i>] [<i><a href="#format_options">&lt;format-options&gt;</a></i>] [<i><a href="#encoding_options">&lt;encoding options&gt;</a></i>] [inputfile [...]]
+			</li>
+			<li>
+				Decoding: flac -d [<i><a href="#general_options">&lt;general-options&gt;</a></i>] [<i><a href="#format_options">&lt;format-options&gt;</a></i>] [<i><a href="#decoding_options">&lt;decoding options&gt;</a></i>]  [FLACfile [...]]
+			</li>
+			<li>
+				Testing: flac -t [<i><a href="#general_options">&lt;general-options&gt;</a></i>] [FLACfile [...]]
+			</li>
+			<li>
+				Analyzing: flac -a [<i><a href="#general_options">&lt;general-options&gt;</a></i>] [<i><a href="#analysis_options">&lt;analysis-options&gt;</a></i>] [FLACfile [...]]
+			</li>
+		</ul>
+		In any case, if no <span class="argument">inputfile</span> is specified, stdin is assumed.  If only one inputfile is specified, it may be "-" for stdin.  When stdin is used as input, <span class="commandname">flac</span> will write to stdout.  Otherwise <span class="commandname">flac</span> will perform the desired operation on each input file to similarly named output files (meaning for encoding, the extension will be replaced with ".flac", or appended with ".flac" if the input file has no extension, and for decoding, the extension will be ".wav" for WAVE output and ".raw" for raw output).  The original file is not deleted unless --delete-input-file is specified.<br />
+		<br />
+		If you are encoding/decoding from stdin to a file, you should use the -o option like so:
+		<ul>
+			<li>
+				flac [options] -o outputfile
+			</li>
+			<li>
+				flac -d [options] -o outputfile
+			</li>
+			</ul>
+			which are better than:
+			<ul>
+			<li>
+				flac [options] &gt; outputfile
+			</li>
+			<li>
+				flac -d [options] &gt; outputfile
+			</li>
+		</ul>
+		since the former allows flac to seek backwards to write the <span class="code">STREAMINFO</span> or RIFF WAVE header contents when necessary.<br />
+		<br />
+		Also, you can force output data to go to stdout using <span class="argument">-c</span>.<br />
+		<br />
+		To encode or decode files that start with a dash, use <span class="argument">--</span> to signal the end of options, to keep the filenames themselves from being treated as options:
+		<ul>
+			<li>
+				<span class="code">flac -V -- -01-filename.wav</span>
+			</li>
+		</ul>
+		The encoding options affect the compression ratio and encoding speed.  The format options are used to tell <span class="commandname">flac</span> the arrangement of samples if the input file (or output file when decoding) is a raw file.  If it is a RIFF WAVE, Wave64, RF64, or AIFF file the format options are not needed since they are read from the file's header.<br />
+		<br />
+		In test mode, <span class="commandname">flac</span> acts just like in decode mode, except no output file is written.  Both decode and test modes detect errors in the stream, but they also detect when the MD5 signature of the decoded audio does not match the stored MD5 signature, even when the bitstream is valid.<br />
+		<br />
+		<span class="commandname">flac</span> can also re-encode FLAC files.  In other words, you can specify a FLAC or Ogg FLAC file as an input to the encoder and it will decoder it and re-encode it according to the options you specify.  It will also preserve all the metadata unless you override it with other options (e.g. specifying new tags, seekpoints, cuesheet, padding, etc.).<br />
+		<br />
+		<span class="commandname">flac</span> has been tuned so that the default settings yield a good speed vs. compression tradeoff for many kinds of input.  However, if you are looking to maximize the compression rate or speed, or want to use the full power of FLAC's metadata system, see <a href="documentation_format_overview.html">About the FLAC Format</a>.<br />
+		<br />
+
+		<a name="tutorial"><font size="+1"><b><u>Tutorial</u></b></font></a><br />
+		<br />
+		Some common <b>encoding</b> tasks using <span class="commandname">flac</span>:<br />
+		<br />
+		<tt><b>flac abc.wav</b></tt><br />
+		Encode <tt>abc.wav</tt> to <tt>abc.flac</tt> using the default compression setting.  <tt>abc.wav</tt> is not deleted.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_delete_input_file">--delete-input-file</a> abc.wav</b></tt><br />
+		Like above, except <tt>abc.wav</tt> is deleted if there were no errors.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_delete_input_file">--delete-input-file</a> <a href="#flac_options_warnings_as_errors">-w</a> abc.wav</b></tt><br />
+		Like above, except <tt>abc.wav</tt> is deleted if there were no errors or warnings.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_best">--best</a> abc.wav</b></tt><br />
+		Encode <tt>abc.wav</tt> to <tt>abc.flac</tt> using the highest compression setting.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_verify">--verify</a> abc.wav</b></tt><br />
+		Encode <tt>abc.wav</tt> to <tt>abc.flac</tt> and internally decode <tt>abc.flac</tt> to make sure it matches <tt>abc.wav</tt>.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_output_name">-o</a> my.flac abc.wav</b></tt><br />
+		Encode <tt>abc.wav</tt> to <tt>my.flac</tt>.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_tag">-T</a> "TITLE=Bohemian Rhapsody" -T "ARTIST=Queen" abc.wav</b></tt><br />
+		Encode <tt>abc.wav</tt> and add some tags at the same time to <tt>abc.flac</tt>.<br />
+		<br />
+		<tt><b>flac *.wav</b></tt><br />
+		Encode all .wav files in the current directory.  NOTE: <a href="faq.html#tools__wildcards_on_windows">Wildcards on Windows</a><br />
+		<br />
+		<tt><b>flac abc.aiff</b></tt><br />
+		Encode <tt>abc.aiff</tt> to <tt>abc.flac</tt>.<br />
+		<br />
+		<tt><b>flac abc.rf64</b></tt><br />
+		Encode <tt>abc.rf64</tt> to <tt>abc.flac</tt>.<br />
+		<br />
+		<tt><b>flac abc.w64</b></tt><br />
+		Encode <tt>abc.w64</tt> to <tt>abc.flac</tt>.<br />
+		<br />
+		<tt><b>flac abc.flac <a href="#flac_options_force">--force</a></b></tt><br />
+		This one's a little tricky: notice that <span class="commandname">flac</span> is in encode mode by default (you have to specify <span class="argument">-d</span> to decode) so this command actually recompresses <tt>abc.flac</tt> back to <tt>abc.flac</tt>.  <span class="argument"><a href="#flac_options_force">--force</a></span> is needed to make sure you really want to overwrite <tt>abc.flac</tt> with a new version.  Why would you want to do this?  It allows you to recompress an existing FLAC file with (usually) higher compression options or a newer version of FLAC and preserve all the metadata like tags too.<br />
+		<br />
+
+		Some common <b>decoding</b> tasks using <span class="commandname">flac</span>:<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_decode">-d</a> abc.flac</b></tt><br />
+		Decode <tt>abc.flac</tt> to <tt>abc.wav</tt>.  <tt>abc.flac</tt> is not deleted.  NOTE: Without <span class="argument"><a href="#flac_options_decode">-d</a></span> it means re-encode <tt>abc.flac</tt> to <tt>abc.flac</tt> (see above).<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_decode">-d</a> <a href="#flac_options_force_aiff_format">--force-aiff-format</a> abc.flac</b></tt><br />
+		<tt><b>flac <a href="#flac_options_decode">-d</a> <a href="#flac_options_output_name">-o</a> abc.aiff abc.flac</b></tt><br />
+		Two different ways of decoding <tt>abc.flac</tt> to <tt>abc.aiff</tt> (AIFF format).  <tt>abc.flac</tt> is not deleted.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_decode">-d</a> <a href="#flac_options_force_rf64_format">--force-rf64-format</a> abc.flac</b></tt><br />
+		<tt><b>flac <a href="#flac_options_decode">-d</a> <a href="#flac_options_output_name">-o</a> abc.rf64 abc.flac</b></tt><br />
+		Two different ways of decoding <tt>abc.flac</tt> to <tt>abc.rf64</tt> (RF64 format).  <tt>abc.flac</tt> is not deleted.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_decode">-d</a> <a href="#flac_options_force_wave64_format">--force-wave64-format</a> abc.flac</b></tt><br />
+		<tt><b>flac <a href="#flac_options_decode">-d</a> <a href="#flac_options_output_name">-o</a> abc.w64 abc.flac</b></tt><br />
+		Two different ways of decoding <tt>abc.flac</tt> to <tt>abc.w64</tt> (Wave64 format).  <tt>abc.flac</tt> is not deleted.<br />
+		<br />
+		<tt><b>flac <a href="#flac_options_decode">-d</a> <a href="#flac_options_decode_through_errors">-F</a> abc.flac</b></tt><br />
+		Decode <tt>abc.flac</tt> to <tt>abc.wav</tt> and don't abort if errors are found (useful for recovering as much as possible from corrupted files).<br />
+		<br />
+		<span class="commandname">flac</span> has many other useful options, described below.<br />
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="general_options"><font size="+1"><b>General Options</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_version" />
+					<span class="argument">-v</span>, <span class="argument">--version</span>
+				</td>
+				<td>
+					Show the <span class="commandname">flac</span> version number.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_help" />
+					<span class="argument">-h</span>, <span class="argument">--help</span>
+				</td>
+				<td>
+					Show basic usage and a list of all options.  Running <span class="commandname">flac</span> without arguments shows the short help screen by default.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_explain" />
+					<span class="argument">-H</span>, <span class="argument">--explain</span>
+				</td>
+				<td>
+					Show detailed explanation of usage and all options.  Running <span class="commandname">flac</span> without arguments shows the short help screen by default.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_decode" />
+					<span class="argument">-d</span>, <span class="argument">--decode</span>
+				</td>
+				<td>
+					Decode (<span class="commandname">flac</span> encodes by default).  <span class="commandname">flac</span> will exit with an exit code of <span class="argument">1</span> (and print a message, even in silent mode) if there were any errors during decoding, including when the MD5 checksum does not match the decoded output.  Otherwise the exit code will be <span class="argument">0</span>.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_test" />
+					<span class="argument">-t</span>, <span class="argument">--test</span>
+				</td>
+				<td>
+					Test (same as <span class="argument">-d</span> except no decoded file is written).  The exit codes are the same as in decode mode.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_analyze" />
+					<span class="argument">-a</span>, <span class="argument">--analyze</span>
+				</td>
+				<td>
+					Analyze (same as <span class="argument">-d</span> except an analysis file is written).  The exit codes are the same as in decode mode.  This option is mainly for developers; the output will be a text file that has data about each frame and subframe.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_stdout" />
+					<span class="argument">-c</span>, <span class="argument">--stdout</span>
+				</td>
+				<td>
+					Write output to stdout.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_silent" />
+					<span class="argument">-s</span>, <span class="argument">--silent</span>
+				</td>
+				<td>
+					Silent: do not show encoding/decoding statistics.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_totally_silent" />
+					<span class="argument">--totally-silent</span>
+				</td>
+				<td>
+					Do not print anything of any kind, including warnings or errors.  The exit code will be the only way to determine successful completion.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_no_utf8_convert" />
+					<span class="argument">--no-utf8-convert</span>
+				</td>
+				<td>
+					Do not convert tags from local charset to UTF-8.  This is useful for scripts, and setting tags in situations where the locale is wrong.  This option must appear before any tag options!
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_warnings_as_errors" />
+					<span class="argument">-w</span>, <span class="argument">--warnings-as-errors</span>
+				</td>
+				<td>
+					Treat all warnings as errors (which cause <span class="commandname">flac</span> to terminate with a non-zero exit code).
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_force" />
+					<span class="argument">-f</span>, <span class="argument">--force</span>
+				</td>
+				<td>
+					Force overwriting of output files.  By default, <span class="commandname">flac</span> warns that the output file already exists and continues to the next file.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_output_name" />
+					<span class="argument">-o filename</span>,<br /><span class="argument">--output-name=filename</span>
+				</td>
+				<td>
+					Force the output file name (usually <span class="commandname">flac</span> just changes the extension).  May only be used when encoding a single file.  May not be used in conjunction with <a href="#flac_options_output_prefix"><span class="argument">--output-prefix</span></a>.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_output_prefix" />
+					<span class="argument">--output-prefix=string</span>
+				</td>
+				<td>
+					Prefix each output file name with the given string.  This can be useful for encoding/decoding files to a different directory.  Make sure if your string is a path name that it ends with a trailing '<span class="argument">/</span>' slash.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_delete_input_file" />
+					<span class="argument">--delete-input-file</span>
+				</td>
+				<td>
+					Automatically delete the input file after a successful encode or decode.  If there was an error (including a verify error) the input file is left intact.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_preserve_modtime" />
+					<span class="argument">--preserve-modtime</span>
+				</td>
+				<td>
+					Output files have their timestamps/permissions set to match those of their inputs (this is default).  Use <span class="argument">--no-preserve-modtime</span> to make output files have the current time and default permissions.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_keep_foreign_metadata" />
+					<span class="argument">--keep-foreign-metadata</span>
+				</td>
+				<td>
+					If encoding, save WAVE, Wave64, RF64, or AIFF non-audio chunks in FLAC metadata.  If decoding, restore any saved non-audio chunks from FLAC metadata when writing the decoded file.  Foreign metadata cannot be transcoded, e.g. WAVE chunks saved in a FLAC file cannot be restored when decoding to AIFF.  Input and output must be regular files (not stdin or stdout).<br />
+<!--
+					<br />
+					Using this option for both encoding then decoding in most cases will yield the exact same WAVE file as the original, metadata and all.  Because there are multiple ways to represent the same data in WAVE, Wave64, RF64, and AIFF, there are currently a few corner cases where the restoration process may not match exactly (but could with some improvement).  The cases are:<br />
+					<ul>
+						<li>The original WAVE/Wave64/RF64 had more than 2 channels and needed remapping to FLAC order</li>
+						<li>The original WAVE/Wave64/RF64 is not spec compliant, e.g. 20 bps in WAVEFORMATEX; restored file will still be a compliant WAVEFORMATEXTENSIBLE</li>
+						<li>Other weird corner cases where the "fmt" chunk is not exactly identical due to there being multiple ways to represent the same thing</li>
+						<li>The original AIFF is in AIFF-C form with compression type "sowt" or "NONE"; currently the restored file will always be in AIFF (uncompressed) form</li>
+					</ul>
+-->
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_skip" />
+					<span class="argument">--skip={#|mm:ss.ss}<br />--skip={#|mm:ss,ss}</span>
+				</td>
+				<td>
+					Skip over the first # of samples of the input.  This works for both encoding and decoding, but not testing.  The alternative form <span class="argument">mm:ss.ss</span> can be used to specify minutes, seconds, and fractions of a second.<br />
+					<br />
+					Note that the use of either a dot or a comma depends on the locale used for the system.<br />
+					<br />
+					Examples:<br />
+					<br />
+					<span class="argument">--skip=123</span> : skip the first 123 samples of the input<br />
+					<span class="argument">--skip=1:23.45</span> : skip the first 1 minute and 23.45 seconds of the input, with a locale using the point as decimal separator<br />
+					<span class="argument">--skip=1:23,45</span> : skip the first 1 minute and 23.45 seconds of the input, with a locale using the comma as decimal separator
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_until" />
+					<span class="argument">--until={#|[+|-]mm:ss.ss}<br />--until={#|[+|-]mm:ss,ss}</span>
+				</td>
+				<td>
+					Stop at the given sample number for each input file.  This works for both encoding and decoding, but not testing.  The given sample number is not included in the decoded output.  The alternative form <span class="argument">mm:ss.ss</span> can be used to specify minutes, seconds, and fractions of a second.  If a <span class="argument">+</span> sign is at the beginning, the <span class="argument">--until</span> point is relative to the <span class="argument">--skip</span> point.  If a <span class="argument">-</span> sign is at the beginning, the <span class="argument">--until</span> point is relative to end of the audio.<br />
+					<br />
+					Note that the use of either a dot or a comma depends on the locale used for the system.<br />
+					<br />
+					Examples:<br />
+					<br />
+					<span class="argument">--until=123</span> : decode only the first 123 samples of the input (samples 0-122, stopping at 123)<br />
+					<span class="argument">--until=1:23.45</span> : decode only the first 1 minute and 23.45 seconds of the input<br />
+					<span class="argument">--until=1:23,45</span> : decode only the first 1 minute and 23.45 seconds of the input, if your locale setting uses a comma as decimal separator<br />
+					<span class="argument">--skip=1:00 --until=+1:23.45</span> : decode 1:00.00 to 2:23.45<br />
+					<span class="argument">--until=-1:23.45</span> : decode everything except the last 1 minute and 23.45 seconds<br />
+					<span class="argument">--until=-0:00</span> : decode until the end of the input (the same as not specifying <span class="argument">--until</span>)
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_ogg" />
+					<span class="argument">--ogg</span>
+				</td>
+				<td>
+					When encoding, generate Ogg FLAC output instead of native FLAC.  Ogg FLAC streams are FLAC streams wrapped in an Ogg transport layer.  The resulting file should have an '.oga' extension and will still be decodable by <span class="commandname">flac</span>.<br />
+					<br />
+					When decoding, force the input to be treated as Ogg FLAC.  This is useful when piping input from stdin or when the filename does not end in '.oga' or '.ogg'.<br />
+					<br />
+					<b>NOTE:</b> Ogg FLAC files created prior to <span class="commandname">flac</span> 1.1.1 used an ad-hoc mapping and do not support seeking.  They should be decoded and re-encoded with <span class="commandname">flac</span> 1.1.1 or later.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_serial_number" />
+					<span class="argument">--serial-number=#</span>
+				</td>
+				<td>
+					When used with --ogg, specifies the serial number to use for the first Ogg FLAC stream, which is then incremented for each additional stream.  When encoding and no serial number is given, <span class="commandname">flac</span> uses a random number for the first stream, then increments it for each additional stream.  When decoding and no number is given, <span class="commandname">flac</span> uses the serial number of the first page.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="analysis_options"><font size="+1"><b>Analysis Options</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_residual_text" />
+					<span class="argument">--residual-text</span>
+				</td>
+				<td>
+					Includes the residual signal in the analysis file.  This will make the file <b>very</b> big, much larger than even the decoded file.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_residual_gnuplot" />
+					<span class="argument">--residual-gnuplot</span>
+				</td>
+				<td>
+					Generates a gnuplot file for every subframe; each file will contain the residual distribution of the subframe.  This will create a <b>lot</b> of files.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="decoding_options"><font size="+1"><b>Decoding Options</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_cue" />
+					<span class="argument">--cue=[#.#][-[#.#]]</span>
+				</td>
+				<td>
+					Set the beginning and ending cuepoints to decode.  The optional first <span class="argument">#.#</span> is the track and index point at which decoding will start; the default is the beginning of the stream.  The optional second <span class="argument">#.#</span> is the track and index point at which decoding will end; the default is the end of the stream.  If the cuepoint does not exist, the closest one before it (for the start point) or after it (for the end point) will be used.  If those don't exist, the start of the stream (for the start point) or end of the stream (for the end point) will be used.  The cuepoints are merely translated into sample numbers then used as --skip and --until.<br />
+					<br />
+					Examples:<br />
+					<br />
+					<span class="argument">--cue=-</span> : decode the entire stream<br />
+					<span class="argument">--cue=4.1</span> : decode from track 4, index 1 to the end of the stream<br />
+					<span class="argument">--cue=4.1-</span> : decode from track 4, index 1 to the end of the stream<br />
+					<span class="argument">--cue=-4.1</span> : decode from the beginning of the stream up to, but not including, track 4, index 1<br />
+					<span class="argument">--cue=2.1-2.4</span> : decode from track 2, index 1, up to, but not including, track 2, index 4<br />
+					<span class="argument">--cue=9.1-10.1</span> : decode from track 9 the way it would be played on a CD player; this works even if the CD has no 10th track.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_decode_through_errors" />
+					<span class="argument">-F</span>,<br /><span class="argument">--decode-through-errors</span>
+				</td>
+				<td>
+					By default <span class="commandname">flac</span> stops decoding with an error and removes the partially decoded file if it encounters a bitstream error.  With <span class="argument">-F</span>, errors are still printed but <span class="commandname">flac</span> will continue decoding to completion.  Note that errors may cause the decoded audio to be missing some samples or have silent sections.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_apply_replaygain_which_is_not_lossless" />
+					<span class="argument">--apply-replaygain-which-is-not-lossless[=&lt;specification&gt;]</span>
+				</td>
+				<td>
+					Applies ReplayGain values while decoding.<br />
+					<br />
+					<b>WARNING: THIS IS NOT LOSSLESS.  DECODED AUDIO WILL NOT BE IDENTICAL TO THE ORIGINAL WITH THIS OPTION</b>.<br />
+					<br />
+					The equals sign and &lt;specification&gt; is optional.  If omitted, the default is <span class="argument">0aLn1</span>.<br />
+					<br />
+					The <span class="argument">&lt;specification&gt;</span> is a shorthand notation for describing how to apply ReplayGain.  All components are optional but order is important.  '<span class="argument">[]</span>' means 'optional'.  '<span class="argument">|</span>' means 'or'.  '<span class="argument">{}</span>' means required.  The format is:<br />
+					<br />
+					&nbsp;&nbsp;<span class="argument">[&lt;preamp&gt;][a|t][l|L][n{0|1|2|3}]</span>
+					<ul>
+						<li>
+							<span class="argument">&lt;preamp&gt;</span><br />
+								&nbsp;&nbsp;A floating point number in dB.  This is added to the existing gain value.
+						</li>
+						<li>
+							<span class="argument">a|t</span><br />
+								&nbsp;&nbsp;Specify '<span class="argument">a</span>' to use the album gain, or '<span class="argument">t</span>' to use the track gain.  If tags for the preferred kind (album/track) do not exist but tags for the other (track/album) do, those will be used instead.
+						</li>
+						<li>
+							<span class="argument">l|L</span><br />
+								&nbsp;&nbsp;Specify '<span class="argument">l</span>' to peak-limit the output, so that the ReplayGain peak value is full-scale.  Specify '<span class="argument">L</span>' to use a 6dB hard limiter that kicks in when the signal approaches full-scale.
+						</li>
+						<li>
+							<span class="argument">n{0|1|2|3}</span><br />
+								&nbsp;&nbsp;Specify the amount of noise shaping.  ReplayGain synthesis happens in floating point; the result is dithered before converting back to integer.  This quantization adds noise.  Noise shaping tries to move the noise where you won't hear it as much.  <span class="argument">0</span> means no noise shaping, <span class="argument">1</span> means 'low', <span class="argument">2</span> means 'medium', <span class="argument">3</span> means 'high'.
+						</li>
+					</ul>
+					For example, the default of <span class="argument">0aLn1</span> means 0dB preamp, use album gain, 6dB hard limit, low noise shaping.<br />
+					<br />
+					<span class="argument">--apply-replaygain-which-is-not-lossless=3</span> means 3dB preamp, use album gain, no limiting, no noise shaping.<br />
+					<br />
+					<span class="commandname">flac</span> uses the ReplayGain tags for the calculation.  If a stream does not have the required tags or they can't be parsed, decoding will continue with a warning, and no ReplayGain is applied to that stream.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="encoding_options"><font size="+1"><b>Encoding Options</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_verify" />
+					<span class="argument">-V</span>, <span class="argument">--verify</span>
+				</td>
+				<td>
+					Verify the encoding process.  With this option, <span class="commandname">flac</span> will create a parallel decoder that decodes the output of the encoder and compares the result against the original.  It will abort immediately with an error if a mismatch occurs.  <span class="argument">-V</span> increases the total encoding time but is guaranteed to catch any unforeseen bug in the encoding process.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_lax" />
+					<span class="argument">--lax</span>
+				</td>
+				<td>
+					Allow encoder to generate non-<a href="format.html#subset">Subset</a> files.  The resulting FLAC file may not be streamable or might have trouble being played in all players (especially hardware devices), so you should only use this option in combination with custom encoding options meant for archival.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_replay_gain" />
+					<span class="argument">--replay-gain</span>
+				</td>
+				<td>
+					Calculate <a href="http://wiki.hydrogenaud.io/index.php?title=ReplayGain_specification">ReplayGain</a> values and store them as FLAC tags, similar to <a href="http://packages.qa.debian.org/v/vorbisgain.html">VorbisGain</a>.  Title gains/peaks will be computed for each input file, and an album gain/peak will be computed for all files.  All input files must have the same resolution, sample rate, and number of channels.  Only mono and stereo files are allowed, and the sample rate must be one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, or 48 kHz.  Also note that this option may leave a few extra bytes in a <span class="code">PADDING</span> block as the exact size of the tags is not known until all files are processed.<br />
+					<br />
+					Note that this option cannot be used when encoding to standard output (stdout).
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_cuesheet" />
+					<span class="argument">--cuesheet=FILENAME</span>
+				</td>
+				<td>
+					Import the given cuesheet file and store it in a <a href="format.html#def_CUESHEET"><span class="code">CUESHEET</span></a> metadata block.  This option may only be used when encoding a single file.  A seekpoint will be added for each index point in the cuesheet to the <a href="format.html#def_SEEKTABLE"><span class="code">SEEKTABLE</span></a> unless <span class="argument">--no-cued-seekpoints</span> is specified.<br />
+					<br />
+					The cuesheet file must be of the sort written by <a href="http://www.goldenhawk.com/cdrwin.htm">CDRwin</a>, <a href="http://www.dcsoft.com/prod03.htm">CDRcue</a>, <a href="http://www.exactaudiocopy.de/">EAC</a>, etc.  See also <a href="http://digitalx.org/cuesheetsyntax.php">cuesheet syntax</a>.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_picture" />
+					<span class="argument">--picture={FILENAME|SPECIFICATION}</span>
+				</td>
+				<td>
+					Import a picture and store it in a <a href="format.html#def_PICTURE"><span class="code">PICTURE</span></a> metadata block.  More than one <span class="argument">--picture</span> command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The <span class="argument">SPECIFICATION</span> is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  <span class="argument">FILENAME</span> is just shorthand for <span class="argument">||||FILENAME</span>.  The format of <span class="argument">SPECIFICATION</span> is<br />
+					<br />
+					<tt>&nbsp;&nbsp;[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE</tt><br />
+					<br />
+					<span class="argument">TYPE</span> is optional; it is a number from one of:<br />
+					<ul>
+						<li><tt>0: Other</tt></li>
+						<li><tt>1: 32x32 pixels 'file icon' (PNG only)</tt></li>
+						<li><tt>2: Other file icon</tt></li>
+						<li><tt>3: Cover (front)</tt></li>
+						<li><tt>4: Cover (back)</tt></li>
+						<li><tt>5: Leaflet page</tt></li>
+						<li><tt>6: Media (e.g. label side of CD)</tt></li>
+						<li><tt>7: Lead artist/lead performer/soloist</tt></li>
+						<li><tt>8: Artist/performer</tt></li>
+						<li><tt>9: Conductor</tt></li>
+						<li><tt>10: Band/Orchestra</tt></li>
+						<li><tt>11: Composer</tt></li>
+						<li><tt>12: Lyricist/text writer</tt></li>
+						<li><tt>13: Recording Location</tt></li>
+						<li><tt>14: During recording</tt></li>
+						<li><tt>15: During performance</tt></li>
+						<li><tt>16: Movie/video screen capture</tt></li>
+						<li><tt>17: A bright coloured fish</tt></li>
+						<li><tt>18: Illustration</tt></li>
+						<li><tt>19: Band/artist logotype</tt></li>
+						<li><tt>20: Publisher/Studio logotype</tt></li>
+					</ul>
+					The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.<br/>
+					<br />
+					<span class="argument">MIME-TYPE</span> is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type <tt>image/jpeg</tt> or <tt>image/png</tt>.  The MIME type can also be --&gt; to mean that <span class="argument">FILE</span> is actually a URL to an image, though this use is discouraged.<br />
+					<br />
+					<span class="argument">DESCRIPTION</span> is optional; the default is an empty string.<br />
+					<br />
+					The next part specifies the resolution and color information.  If the <span class="argument">MIME-TYPE</span> is <tt>image/jpeg</tt>, <tt>image/png</tt>, or <tt>image/gif</tt>, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.<br />
+					<br />
+					<span class="argument">FILE</span> is the path to the picture file to be imported, or the URL if MIME type is --&gt;<br />
+					<br />
+					For example, the specification <span class="argument">|image/jpeg|||../cover.jpg</span> will embed the JPEG file at <tt>../cover.jpg</tt>, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.<br />
+					<br />
+					The specification <span class="argument">4|--&gt;|CD|320x300x24/173|http://blah.blah/backcover.tiff</span> will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_sector_align" />
+					<span class="argument">--sector-align</span>
+				</td>
+				<td>
+					Align encoding of multiple CD format files on sector boundaries.  This option is only allowed when encoding files all of which have a 44.1kHz sample rate and 2 channels.  With <span class="argument">--sector-align</span>, the encoder will align the resulting .flac streams so that their lengths are even multiples of a CD sector (1/75th of a second, or 588 samples).  It does this by carrying over any partial sector at the end of each file to the next stream.  The last stream will be padded to alignment with zeroes.<br />
+					<br />
+					This option will have no effect if the files are already aligned (as is the normally the case with WAVE files ripped from a CD).  <span class="commandname">flac</span> can only align a set of files given in one invocation of <span class="commandname">flac</span>.<br />
+					<br />
+					<b>WARNING:</b> The ordering of files is important!  If you give a command like '<span class="code">flac --sector-align *.wav</span>' the shell may not expand the wildcard to the order you expect.  To be safe you should '<span class="code">echo *.wav</span>' first to confirm the order, or be explicit like '<span class="code">flac --sector-align 8.wav 9.wav 10.wav</span>'.<br />
+					<br />
+					<b>NOTE:</b>This option is DEPRECATED and may not exist in future version of <span class="commandname">flac</span>.  <a href="http://www.etree.org/shnutils/shntool/">shntool</a> provides similar functionality.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_ignore_chunk_sizes" />
+					<span class="argument">--ignore-chunk-sizes</span>
+				</td>
+				<td>
+					When encoding to <span class="commandname">flac</span>, ignore the file size headers in WAV and AIFF files to attempt to work around problems with over-sized or malformed files.<br />
+					<br />
+					WAV and AIFF files both have an unsigned 32 bit numbers in the file header which specifes the length of audio data. Since this number is unsigned 32 bits, that limits the size of a valid file to being just over 4 Gigabytes. Files larger than this are mal-formed, but should be read correctly using this option. <br />
+					<br />
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_seekpoint" />
+					<span class="argument">-S {#|X|#x|#s}</span>,<br /><span class="argument">--seekpoint={#|X|#x|#s}</span>
+				</td>
+				<td>
+					Include a point or points in a <span class="code">SEEKTABLE</span>:<br />
+					<ul>
+					<li>
+						<span class="argument">#&nbsp;</span> : a specific sample number for a seek point
+					</li>
+					<li>
+						<span class="argument">X&nbsp;</span> : a placeholder point (always goes at the end of the <span class="code">SEEKTABLE</span>)
+					</li>
+					<li>
+						<span class="argument">#x</span> : # evenly spaced seekpoints, the first being at sample 0
+					</li>
+					<li>
+						<span class="argument">#s</span> : a seekpoint every # seconds; # does not have to be a whole number, it can be, for example, <span class="argument">9.5</span>, meaning a seekpoint every 9.5 seconds
+					</li>
+					</ul>
+					You may use many -S options; the resulting <span class="code">SEEKTABLE</span> will be the unique-ified union of all such values.<br />
+					With no -S options, flac defaults to '-S 10s'.  Use --no-seektable for no <span class="code">SEEKTABLE</span>.<br />
+					<b>NOTE:</b> -S #x and -S #s will not work if the encoder can't determine the input size before starting.<br />
+					<b>NOTE:</b> if you use -S # and # is &gt;= samples in the input, there will be either no seek point entered (if the input size is determinable before encoding starts) or a placeholder point (if input size is not determinable).<br />
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_padding" />
+					<span class="argument">-P #</span>, <span class="argument">--padding=#</span>
+				</td>
+				<td>
+					Tell the encoder to write a <span class="code">PADDING</span> metadata block of the given length (in bytes) after the <span class="code">STREAMINFO</span> block.  This is useful if you plan to tag the file later with an <span class="code">APPLICATION</span> block; instead of having to rewrite the entire file later just to insert your block, you can write directly over the <span class="code">PADDING</span> block.  Note that the total length of the <span class="code">PADDING</span> block will be 4 bytes longer than the length given because of the 4 metadata block header bytes.  You can force no <span class="code">PADDING</span> block at all to be written with <span class="argument">--no-padding</span>.  The encoder writes a <span class="code">PADDING</span> block of 8192 bytes by default (or 65536 bytes if the input audio stream is more than 20 minutes long).
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_tag" />
+					<span class="argument">-T FIELD=VALUE</span>,<br /><span class="argument">--tag=FIELD=VALUE</span>
+				</td>
+				<td>
+					Add a FLAC tag.  The comment must adhere to the Vorbis comment spec (which FLAC tags implement), i.e. the FIELD must contain only legal characters, terminated by an 'equals' sign.  Make sure to quote the comment if necessary.  This option may appear more than once to add several comments.  NOTE: all tags will be added to all encoded files.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_tag_from_file" />
+					<span class="argument">--tag-from-file=FIELD=FILENAME</span>
+				</td>
+				<td>
+					Like <a href="#flac_options_tag"><span class="argument">--tag</span></a>, except FILENAME is a file whose contents will be read verbatim to set the tag value.  The contents will be converted to UTF-8 from the local charset.  This can be used to store a cuesheet in a tag (e.g. <span class="argument">--tag-from-file="CUESHEET=image.cue"</span>).  Do not try to store binary data in tag fields!  Use APPLICATION blocks for that.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_blocksize" />
+					<span class="argument">-b #</span>, <span class="argument">--blocksize=#</span>
+				</td>
+				<td>
+					Specify the block size in samples.  Subset streams must use one of 192/576/1152/2304/4608/256/512/1024/2048/4096 (and 8192/16384 if the sample rate is &gt;48kHz).  The reference encoder uses the same block size for the entire stream.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_mid_side" />
+					<span class="argument">-m</span>, <span class="argument">--mid-side</span>
+				</td>
+				<td>
+					Enable mid-side coding (only for stereo streams).  Tends to increase compression by a few percent on average.  For each block both the stereo pair and mid-side versions of the block will be encoded, and smallest resulting frame will be stored.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_adaptive_mid_side" />
+					<span class="argument">-M</span>, <span class="argument">--adaptive-mid-side</span>
+				</td>
+				<td>
+					Enable adaptive mid-side coding (only for stereo streams).  Like <span class="argument">-m</span> but the encoder adaptively switches between independent and mid-side coding, which is faster but yields less compression than <span class="argument">-m</span> (which does an exhaustive search).
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_levels" />
+					<span class="argument">-0 .. -8</span>
+				</td>
+				<td>
+					Fastest compression .. highest compression.  The default is <span class="argument">-5</span>.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_0" />
+					<span class="argument">-0</span>, <span class="argument">--compression-level-0</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 0 -b 1152 -r 3</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_1" />
+					<span class="argument">-1</span>, <span class="argument">--compression-level-1</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 0 -b 1152 -M -r 3</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_2" />
+					<span class="argument">-2</span>, <span class="argument">--compression-level-2</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 0 -b 1152 -m -r 3</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_3" />
+					<span class="argument">-3</span>, <span class="argument">--compression-level-3</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 6 -b 4096 -r 4</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_4" />
+					<span class="argument">-4</span>, <span class="argument">--compression-level-4</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 8 -b 4096 -M -r 4</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_5" />
+					<span class="argument">-5</span>, <span class="argument">--compression-level-5</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 8 -b 4096 -m -r 5</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_6" />
+					<span class="argument">-6</span>, <span class="argument">--compression-level-6</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 8 -b 4096 -m -r 6 -A tukey(0.5);partial_tukey(2)</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_7" />
+					<span class="argument">-7</span>, <span class="argument">--compression-level-7</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 12 -b 4096 -m -r 6 -A tukey(0.5);partial_tukey(2)</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_level_8" />
+					<span class="argument">-8</span>, <span class="argument">--compression-level-8</span>
+				</td>
+				<td>
+					Synonymous with <span class="argument">-l 12 -b 4096 -m -r 6 -A tukey(0.5);partial_tukey(2);punchout_tukey(3)</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_fast" />
+					<span class="argument">--fast</span>
+				</td>
+				<td>
+					Fastest compression.  Currently synonymous with <span class="argument">-0</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_best" />
+					<span class="argument">--best</span>
+				</td>
+				<td>
+					Highest compression.  Currently synonymous with <span class="argument">-8</span>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_exhaustive_model_search" />
+					<span class="argument">-e</span>,<br /><span class="argument">--exhaustive-model-search</span>
+				</td>
+				<td>
+					Exhaustive model search (expensive!).  Normally the encoder estimates the best model to use and encodes once based on the estimate.  With an exhaustive model search, the encoder will generate subframes for every order and use the smallest.  If the max LPC order is high this can significantly increase the encode time but can shave off another 0.5%.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_apodization" />
+					<span class="argument">-A "function"</span>, <span class="argument">--apodization="function"</span>
+				</td>
+				<td>
+					Window audio data with given the apodization function.  The functions are: bartlett, bartlett_hann, blackman, blackman_harris_4term_92db, connes, flattop, gauss(STDDEV), hamming, hann, kaiser_bessel, nuttall, rectangle, triangle, tukey(P), partial_tukey(n[/ov[/P]]), punchout_tukey(n[/ov[/P]]), welch.<br />
+					For gauss(STDDEV), STDDEV is the standard deviation (0&lt;STDDEV&lt;=0.5).<br />
+					For tukey(P), P specifies the fraction of the window that is tapered (0&lt;=P&lt;=1; P=0 corresponds to "rectangle" and P=1 corresponds to "hann").<br />
+					For partial_tukey(n) and punchout_tukey(n), n apodization functions are added that span different parts of each block. Values of 2 to 6 seem to yield sane results. If necessary, an overlap can be specified, as can be the taper parameter, for example partial_tukey(2/0.2) or partial_tukey(2/0.2/0.5). ov should be smaller than 1 and can be negative.<br />
+					Please note that P, STDDEV and ov are locale specific, so a comma as decimal separator might be required instead of a dot.<br />
+					More than one -A option (up to 32) may be used.  Any function that is specified erroneously is silently dropped.  The encoder chooses suitable defaults in the absence of any -A options; any -A option specified replaces the default(s).<br />
+					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.  Multiple functions can greatly increase the encoding time.<br />
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_max_lpc_order" />
+					<span class="argument">-l #</span>, <span class="argument">--max-lpc-order=#</span>
+				</td>
+				<td>
+					Specifies the maximum LPC order.  This number must be &lt;= 32.  For Subset streams, it must be &lt;=12 if the sample rate is &lt;=48kHz.  If 0, the encoder will not attempt generic linear prediction, and use only fixed predictors.  Using fixed predictors is faster but usually results in files being 5-10% larger.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_qlp_coeff_precision" />
+					<span class="argument">-q #</span>,<br /><span class="argument">--qlp-coeff-precision=#</span>
+				</td>
+				<td>
+					Specifies the precision of the quantized LP coefficients, in bits.  The default is <span class="argument">-q 0</span>, which means let the encoder decide based on the signal.  Unless you really know your input file it's best to leave this up to the encoder.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_qlp_coeff_precision_search" />
+					<span class="argument">-p</span>,<br /><span class="argument">--qlp-coeff-precision-search</span>
+				</td>
+				<td>
+					Do exhaustive LP coefficient quantization optimization.  This option overrides any <span class="argument">-q</span> option.  It is expensive and typically will only improve the compression a tiny fraction of a percent.  <span class="argument">-q</span> has no effect when <span class="argument">-l 0</span> is used.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_rice_partition_order" />
+					<span class="argument">-r [#,]#</span>,<br /><span class="argument">--rice-partition-order=[#,]#</span>
+				</td>
+				<td>
+					Set the [min,]max residual partition order.  The min value defaults to 0 if unspecified.<br />
+					<br />
+					By default the encoder uses a single Rice parameter for the subframe's entire residual.  With this option, the residual is iteratively partitioned into 2^min# .. 2^max# pieces, each with its own Rice parameter.  Higher values of max# yield diminishing returns.  The most bang for the buck is usually with <span class="argument">-r 2,2</span> (more for higher block sizes).  This usually shaves off about 1.5%.  The technique tends to peak out about when blocksize/(2^n)=128.  Use <span class="argument">-r 0,15</span> to force the highest degree of optimization.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="format_options"><font size="+1"><b>Format Options</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_endian" />
+					<span class="argument">--endian={big|little}</span>
+				</td>
+				<td>
+					Specify big-endian or little-endian byte order in the raw file.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_channels" />
+					<span class="argument">--channels=#</span>
+				</td>
+				<td>
+					Specify the number of channels in the raw file.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_bps" />
+					<span class="argument">--bps=#</span>
+				</td>
+				<td>
+					Specify the number of bits per sample in the raw file.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_sample_rate" />
+					<span class="argument">--sample-rate=#</span>
+				</td>
+				<td>
+					Specify the sample rate of the raw file.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_sign" />
+					<span class="argument">--sign={signed|unsigned}</span>
+				</td>
+				<td>
+					Specify that the samples in the raw file are signed or unsigned (the default is signed).
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_input_size" />
+					<span class="argument">--input-size=#</span>
+				</td>
+				<td>
+					Specify the size of the raw input in bytes.  If you are encoding raw samples from stdin, you must set this option in order to be able to use --skip, --until, --cuesheet, or other options that need to know the size of the input beforehand.  If the size given is greater than what is found in the input stream, the encoder will complain about an unexpected end-of-file.  If the size given is less, samples will be truncated.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_force_raw_format" />
+					<span class="argument">--force-raw-format</span>
+				</td>
+				<td>
+					Treat the input file (or output file if decoding) as a raw file, regardless of the extension.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_force_aiff_format" />
+					<span class="argument">--force-aiff-format</span>
+				</td>
+				<td>
+					Force the decoder to output AIFF format.  This option is not needed if the output filename (as set by -o) ends with .aif or .aiff.  Also, this option has no effect when encoding since input AIFF is auto-detected.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_force_rf64_format" />
+					<span class="argument">--force-rf64-format</span>
+				</td>
+				<td>
+					Force the decoder to output RF64 format.  This option is not needed if the output filename (as set by -o) ends with .rf64.  Also, this option has no effect when encoding since input RF64 is auto-detected.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="flac_options_force_wave64_format" />
+					<span class="argument">--force-wave64-format</span>
+				</td>
+				<td>
+					Force the decoder to output Wave64 format.  This option is not needed if the output filename (as set by -o) ends with .w64.  Also, this option has no effect when encoding since input Wave64 is auto-detected.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="negative_options"><font size="+1"><b>Negative Options</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<span class="argument">--no-adaptive-mid-side</span><br />
+					<span class="argument">--no-cued-seekpoints</span><br />
+					<span class="argument">--no-decode-through-errors</span><br />
+					<span class="argument">--no-delete-input-file</span><br />
+					<span class="argument">--no-escape-coding</span><br />
+					<span class="argument">--no-exhaustive-model-search</span><br />
+					<span class="argument">--no-ignore-chunk-sizes</span><br />
+					<span class="argument">--no-lax</span><br />
+					<span class="argument">--no-mid-side</span><br />
+					<span class="argument">--no-ogg</span><br />
+					<span class="argument">--no-padding</span><br />
+					<span class="argument">--no-preserve-modtime</span><br />
+					<span class="argument">--no-qlp-coeff-prec-search</span><br />
+					<span class="argument">--no-residual-gnuplot</span><br />
+					<span class="argument">--no-residual-text</span><br />
+					<span class="argument">--no-sector-align</span><br />
+					<span class="argument">--no-seektable</span><br />
+					<span class="argument">--no-silent</span><br />
+					<span class="argument">--no-verify</span>
+					<span class="argument">--no-warnings-as-errors</span>
+				</td>
+				<td>
+					Can all be used to turn off a particular option.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+		<a name="option_index"><font size="+1"><b><u>Option Index</u></b></font></a><br />
+		<br />
+		<a href="#flac_options_level_0"><span class="argument">-0</span></a><br />
+		<a href="#flac_options_level_1"><span class="argument">-1</span></a><br />
+		<a href="#flac_options_level_2"><span class="argument">-2</span></a><br />
+		<a href="#flac_options_level_3"><span class="argument">-3</span></a><br />
+		<a href="#flac_options_level_4"><span class="argument">-4</span></a><br />
+		<a href="#flac_options_level_5"><span class="argument">-5</span></a><br />
+		<a href="#flac_options_level_6"><span class="argument">-6</span></a><br />
+		<a href="#flac_options_level_7"><span class="argument">-7</span></a><br />
+		<a href="#flac_options_level_8"><span class="argument">-8</span></a><br />
+		<a href="#flac_options_apodization"><span class="argument">-A</span></a><br />
+		<a href="#flac_options_analyze"><span class="argument">-a</span></a><br />
+		<a href="#flac_options_adaptive_mid_side"><span class="argument">--adaptive-mid-side</span></a><br />
+		<a href="#flac_options_analyze"><span class="argument">--analyze</span></a><br />
+		<a href="#flac_options_apodization"><span class="argument">--apodization</span></a><br />
+		<a href="#flac_options_apply_replaygain_which_is_not_lossless"><span class="argument">--apply-replaygain-which-is-not-lossless</span></a><br />
+		<a href="#flac_options_blocksize"><span class="argument">-b</span></a><br />
+		<a href="#flac_options_best"><span class="argument">--best</span></a><br />
+		<a href="#flac_options_blocksize"><span class="argument">--blocksize</span></a><br />
+		<a href="#flac_options_bps"><span class="argument">--bps</span></a><br />
+		<a href="#flac_options_stdout"><span class="argument">-c</span></a><br />
+		<a href="#flac_options_channels"><span class="argument">--channels</span></a><br />
+		<a href="#flac_options_level_0"><span class="argument">--compression-level-0</span></a><br />
+		<a href="#flac_options_level_1"><span class="argument">--compression-level-1</span></a><br />
+		<a href="#flac_options_level_2"><span class="argument">--compression-level-2</span></a><br />
+		<a href="#flac_options_level_3"><span class="argument">--compression-level-3</span></a><br />
+		<a href="#flac_options_level_4"><span class="argument">--compression-level-4</span></a><br />
+		<a href="#flac_options_level_5"><span class="argument">--compression-level-5</span></a><br />
+		<a href="#flac_options_level_6"><span class="argument">--compression-level-6</span></a><br />
+		<a href="#flac_options_level_7"><span class="argument">--compression-level-7</span></a><br />
+		<a href="#flac_options_level_8"><span class="argument">--compression-level-8</span></a><br />
+		<a href="#flac_options_cue"><span class="argument">--cue</span></a><br />
+		<a href="#flac_options_cuesheet"><span class="argument">--cuesheet</span></a><br />
+		<a href="#flac_options_decode"><span class="argument">-d</span></a><br />
+		<a href="#flac_options_decode"><span class="argument">--decode</span></a><br />
+		<a href="#flac_options_decode_through_errors"><span class="argument">--decode-through-errors</span></a><br />
+		<a href="#flac_options_delete_input_file"><span class="argument">--delete-input-file</span></a><br />
+		<a href="#flac_options_exhaustive_model_search"><span class="argument">-e</span></a><br />
+		<a href="#flac_options_endian"><span class="argument">--endian</span></a><br />
+		<a href="#flac_options_exhaustive_model_search"><span class="argument">--exhaustive-model-search</span></a><br />
+		<a href="#flac_options_explain"><span class="argument">--explain</span></a><br />
+		<a href="#flac_options_decode_through_errors"><span class="argument">-F</span></a><br />
+		<a href="#flac_options_force"><span class="argument">-f</span></a><br />
+		<a href="#flac_options_fast"><span class="argument">--fast</span></a><br />
+		<a href="#flac_options_force_raw_format"><span class="argument">--force-raw-format</span></a><br />
+		<a href="#flac_options_force_aiff_format"><span class="argument">--force-aiff-format</span></a><br />
+		<a href="#flac_options_force_rf64_format"><span class="argument">--force-rf64-format</span></a><br />
+		<a href="#flac_options_force_wave64_format"><span class="argument">--force-wave64-format</span></a><br />
+		<a href="#flac_options_force"><span class="argument">--force</span></a><br />
+		<a href="#flac_options_explain"><span class="argument">-H</span></a><br />
+		<a href="#flac_options_help"><span class="argument">-h</span></a><br />
+		<a href="#flac_options_help"><span class="argument">--help</span></a><br />
+		<a href="#flac_options_ignore_chunk_sizes"><span class="argument">--ignore-chunk-sizes</span></a><br />
+		<a href="#flac_options_input_size"><span class="argument">--input-size</span></a><br />
+		<a href="#flac_options_keep_foreign_metadata"><span class="argument">--keep-foreign-metadata</span></a><br />
+		<a href="#flac_options_max_lpc_order"><span class="argument">-l</span></a><br />
+		<a href="#flac_options_lax"><span class="argument">--lax</span></a><br />
+		<a href="#flac_options_adaptive_mid_side"><span class="argument">-M</span></a><br />
+		<a href="#flac_options_mid_side"><span class="argument">-m</span></a><br />
+		<a href="#flac_options_max_lpc_order"><span class="argument">--max-lpc-order</span></a><br />
+		<a href="#flac_options_mid_side"><span class="argument">--mid-side</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-adaptive-mid-side</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-cued-seekpoints</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-decode-through-errors</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-delete-input-file</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-escape-coding</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-exhaustive-model-search</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-keep-foreign-metadata</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-lax</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-mid-side</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-ogg</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-padding</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-preserve-modtime</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-qlp-coeff-prec-search</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-residual-gnuplot</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-residual-text</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-sector-align</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-seektable</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-silent</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-verify</span></a><br />
+		<a href="#negative_options"><span class="argument">--no-warnings-as-errors</span></a><br />
+		<a href="#flac_options_no_utf8_convert"><span class="argument">--no-utf8-convert</span></a><br />
+		<a href="#flac_options_output_name"><span class="argument">-o</span></a><br />
+		<a href="#flac_options_ogg"><span class="argument">--ogg</span></a><br />
+		<a href="#flac_options_output_name"><span class="argument">--output-name</span></a><br />
+		<a href="#flac_options_output_prefix"><span class="argument">--output-prefix</span></a><br />
+		<a href="#flac_options_padding"><span class="argument">-P</span></a><br />
+		<a href="#flac_options_qlp_coeff_precision_search"><span class="argument">-p</span></a><br />
+		<a href="#flac_options_padding"><span class="argument">--padding</span></a><br />
+		<a href="#flac_options_picture"><span class="argument">--picture</span></a><br />
+		<a href="#flac_options_qlp_coeff_precision"><span class="argument">-q</span></a><br />
+		<a href="#flac_options_qlp_coeff_precision"><span class="argument">--qlp-coeff-precision</span></a><br />
+		<a href="#flac_options_qlp_coeff_precision_search"><span class="argument">--qlp-coeff-precision-search</span></a><br />
+		<a href="#flac_options_rice_partition_order"><span class="argument">-r</span></a><br />
+		<a href="#flac_options_replay_gain"><span class="argument">--replay-gain</span></a><br />
+		<a href="#flac_options_residual_gnuplot"><span class="argument">--residual-gnuplot</span></a><br />
+		<a href="#flac_options_residual_text"><span class="argument">--residual-text</span></a><br />
+		<a href="#flac_options_rice_partition_order"><span class="argument">--rice-partition-order</span></a><br />
+		<a href="#flac_options_seekpoint"><span class="argument">-S</span></a><br />
+		<a href="#flac_options_silent"><span class="argument">-s</span></a><br />
+		<a href="#flac_options_sample_rate"><span class="argument">--sample-rate</span></a><br />
+		<a href="#flac_options_sector_align"><span class="argument">--sector-align</span></a><br />
+		<a href="#flac_options_seekpoint"><span class="argument">--seekpoint</span></a><br />
+		<a href="#flac_options_serial_number"><span class="argument">--serial-number</span></a><br />
+		<a href="#flac_options_sign"><span class="argument">--sign</span></a><br />
+		<a href="#flac_options_silent"><span class="argument">--silent</span></a><br />
+		<a href="#flac_options_skip"><span class="argument">--skip</span></a><br />
+		<a href="#flac_options_stdout"><span class="argument">--stdout</span></a><br />
+		<a href="#flac_options_tag"><span class="argument">-T</span></a><br />
+		<a href="#flac_options_test"><span class="argument">-t</span></a><br />
+		<a href="#flac_options_tag"><span class="argument">--tag</span></a><br />
+		<a href="#flac_options_tag_from_file"><span class="argument">--tag-from-file</span></a><br />
+		<a href="#flac_options_test"><span class="argument">--test</span></a><br />
+		<a href="#flac_options_totally_silent"><span class="argument">--totally-silent</span></a><br />
+		<a href="#flac_options_until"><span class="argument">--until</span></a><br />
+		<a href="#flac_options_verify"><span class="argument">-V</span></a><br />
+		<a href="#flac_options_version"><span class="argument">-v</span></a><br />
+		<a href="#flac_options_verify"><span class="argument">--verify</span></a><br />
+		<a href="#flac_options_warnings_as_errors"><span class="argument">-w</span></a><br />
+		<a href="#flac_options_warnings_as_errors"><span class="argument">--warnings-as-errors</span></a><br />
+		<a href="#flac_options_version"><span class="argument">--version</span></a><br />
+
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/documentation_tools_metaflac.html b/doc/html/documentation_tools_metaflac.html
new file mode 100644
index 0000000..122d70b
--- /dev/null
+++ b/doc/html/documentation_tools_metaflac.html
@@ -0,0 +1,566 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - documentation</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		<a name="metaflac">metaflac</a>
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		<a name="toc"><font size="+1"><b><u>Table of Contents</u></b></font></a>
+		<ul>
+			<li><a href="#usage">General Usage</a></li>
+			<li><a href="#global_options">Global Options</a></li>
+			<li><a href="#shorthand_operations">Shorthand Operations</a></li>
+			<li><a href="#major_operations">Major Operations</a></li>
+			<li><a href="#option_index">Option Index</a></li>
+		</ul>
+		<a name="usage"><font size="+1"><b><u>General Usage</u></b></font></a><br />
+		<br />
+		<span class="commandname">metaflac</span> is the command-line <span class="code">.flac</span> file metadata editor.  You can use it to list the contents of metadata blocks, edit, delete or insert blocks, and manage padding.<br />
+		<br />
+		<span class="commandname">metaflac</span> takes a set of "options" (though some are not optional) and a set of FLAC files to operate on.  There are three kinds of "options":
+		<ul>
+			<li>
+				Major operations, which specify a mode of operation like listing blocks, removing blocks, etc.  These will have sub-operations describing exactly what is to be done.
+			</li>
+			<li>
+				Shorthand operations, which are convenient synonyms for major operations.  For example, there is a shorthand operation <span class="argument">--show-sample-rate</span> that shows just the sample rate field from the <span class="code">STREAMINFO</span> metadata block.
+			</li>
+			<li>
+				Global options, which affect all the operations.
+			</li>
+		</ul>
+		All of these are described in the tables below.  At least one shorthand or major operation must be supplied.  You can use multiple shorthand operations to do more than one thing to a file or set of files.  Most of the common things to do to metadata have shorthand operations.  As an example, here is how to show the MD5 signatures for a set of three FLAC files:<br />
+		<br />
+		<span class="code">metaflac --show-md5sum file1.flac file2.flac file3.flac</span><br />
+		<br />
+		Another example; this removes all DESCRIPTION and COMMENT tags in a set of FLAC files, and uses the <span class="argument">--preserve-modtime</span> global option to keep the FLAC file modification times the same (usually when files are edited the modification time is set to the current time):<br />
+		<br />
+		<span class="code">metaflac --preserve-modtime --remove-tag=DESCRIPTION --remove-tag=COMMENT file1.flac file2.flac file3.flac</span><br />
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="global_options"><font size="+1"><b>Global Options</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_options_preserve_modtime" />
+					<span class="argument">--preserve-modtime</span>
+				</td>
+				<td>
+					Preserve the original modification time in spite of edits.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_options_with_filename" />
+					<span class="argument">--with-filename</span>
+				</td>
+				<td>
+					Prefix each output line with the FLAC file name (the default if more than one FLAC file is specified).
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_options_no_filename" />
+					<span class="argument">--no-filename</span>
+				</td>
+				<td>
+					Do not prefix each output line with the FLAC file name (the default if only one FLAC file is specified)
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_options_no_utf8_convert" />
+					<span class="argument">--no-utf8-convert</span>
+				</td>
+				<td>
+					Do not convert tags from UTF-8 to local charset, or vice versa.  This is useful for scripts, and setting tags in situations where the locale is wrong.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_options_dont_use_padding" />
+					<span class="argument">--dont-use-padding</span>
+				</td>
+				<td>
+					By default <span class="commandname">metaflac</span> tries to use padding where possible to avoid rewriting the entire file if the metadata size changes.  Use this option to tell metaflac to not take advantage of padding this way.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="shorthand_operations"><font size="+1"><b>Shorthand Operations</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_md5sum" />
+					<span class="argument">--show-md5sum</span>
+				</td>
+				<td>
+					Show the MD5 signature from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_min_blocksize" />
+					<span class="argument">--show-min-blocksize</span>
+				</td>
+				<td>
+					Show the minimum block size from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_max_blocksize" />
+					<span class="argument">--show-max-blocksize</span>
+				</td>
+				<td>
+					Show the maximum block size from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_min_framesize" />
+					<span class="argument">--show-min-framesize</span>
+				</td>
+				<td>
+					Show the minimum frame size from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_max_framesize" />
+					<span class="argument">--show-max-framesize</span>
+				</td>
+				<td>
+					Show the maximum frame size from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_sample_rate" />
+					<span class="argument">--show-sample-rate</span>
+				</td>
+				<td>
+					Show the sample rate from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_channels" />
+					<span class="argument">--show-channels</span>
+				</td>
+				<td>
+					Show the number of channels from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_bps" />
+					<span class="argument">--show-bps</span>
+				</td>
+				<td>
+					Show the # of bits per sample from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_total_samples" />
+					<span class="argument">--show-total-samples</span>
+				</td>
+				<td>
+					Show the total # of samples from the <span class="code">STREAMINFO</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_vendor_tag" />
+					<span class="argument">--show-vendor-tag</span>
+				</td>
+				<td>
+					Show the vendor string from the <span class="code">VORBIS_COMMENT</span> block.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_show_tag" />
+					<span class="argument">--show-tag=NAME</span>
+				</td>
+				<td>
+					Show all tags where the field name matches <span class="argument">NAME</span>.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_remove_tag" />
+					<span class="argument">--remove-tag=NAME</span>
+				</td>
+				<td>
+					Remove all tags whose field name is <span class="argument">NAME</span>.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_remove_first_tag" />
+					<span class="argument">--remove-first-tag=NAME</span>
+				</td>
+				<td>
+					Remove first tag whose field name is <span class="argument">NAME</span>.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_remove_all_tags" />
+					<span class="argument">--remove-all-tags</span>
+				</td>
+				<td>
+					Remove all tags, leaving only the vendor string.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_set_tag" />
+					<span class="argument">--set-tag=FIELD</span>
+				</td>
+				<td>
+					Add a tag.  The <span class="argument">FIELD</span> must comply with the Vorbis comment spec, of the form <span class="argument">NAME=VALUE</span>.  If there is currently no tag block, one will be created.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_set_tag_from_file" />
+					<span class="argument">--set-tag-from-file=FIELD</span>
+				</td>
+				<td>
+					Like <a href="#metaflac_shorthand_set_tag"><span class="argument">--set-tag</span></a>, except the VALUE is a filename whose contents will be read verbatim to set the tag value.  Unless <a href="#metaflac_options_no_utf8_convert"><span class="argument">--no-utf8-convert</span></a> is specified, the contents will be converted to UTF-8 from the local charset.  This can be used to store a cuesheet in a tag (e.g. <span class="argument">--set-tag-from-file="CUESHEET=image.cue"</span>).  Do not try to store binary data in tag fields!  Use APPLICATION blocks for that.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_import_tags_from" />
+					<span class="argument">--import-tags-from=FILE</span>
+				</td>
+				<td>
+					Import tags from a file.  Use <span class="argument">-</span> for stdin.  Each line should be of the form <span class="argument">NAME=VALUE</span>.  Multi-line comments are currently not supported.  Specify <span class="argument">--remove-all-tags</span> and/or <a href="#metaflac_options_no_utf8_convert"><span class="argument">--no-utf8-convert</span></a> before <span class="argument">--import-tags-from</span> if necessary.  If <span class="argument">FILE</span> is <span class="argument">-</span> (stdin), only one FLAC file may be specified.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_export_tags_to" />
+					<span class="argument">--export-tags-to=FILE</span>
+				</td>
+				<td>
+					Export tags to a file.  Use <span class="argument">-</span> for stdin.  Each line will be of the form <span class="argument">NAME=VALUE</span>.  Specify <a href="#metaflac_options_no_utf8_convert"><span class="argument">--no-utf8-convert</span></a> if necessary.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_import_cuesheet_from" />
+					<span class="argument">--import-cuesheet-from=FILE</span>
+				</td>
+				<td>
+					Import a cuesheet from a file.  Use <span class="argument">-</span> for stdin.  Only one FLAC file may be specified.  A seekpoint will be added for each index point in the cuesheet to the <span class="code">SEEKTABLE</span> unless <span class="argument">--no-cued-seekpoints</span> is specified.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_export_cuesheet_to" />
+					<span class="argument">--export-cuesheet-to=FILE</span>
+				</td>
+				<td>
+					Export <span class="code">CUESHEET</span> block to a cuesheet file, suitable for use by CD authoring software.  Use <span class="argument">-</span> for stdout.  Only one FLAC file may be specified on the command line.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_import_picture_from" />
+					<span class="argument">--import-picture-from={FILENAME|SPECIFICATION}</span>
+				</td>
+				<td>
+					Import a picture and store it in a <a href="format.html#def_PICTURE"><span class="code">PICTURE</span></a> metadata block.  See the <span class="commandname">flac</span> option <span class="argument"><a href="documentation_tools_flac.html#flac_options_picture">--picture</a></span> for an explanation of the <span class="argument">SPECIFICATION</span> syntax.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_export_picture_to" />
+					<span class="argument">--export-picture-to=FILE</span>
+				</td>
+				<td>
+					Export <span class="code">PICTURE</span> block to a file.  Use <span class="argument">-</span> for stdout.  Only one FLAC file may be specified on the command line.  The first <span class="code">PICTURE</span> block will be exported unless <span class="argument">--export-picture-to</span> is preceded by a <span class="argument">--block-number=#</span> option to specify the exact metadata block to extract.  Note that the block number is the one shown by --list.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_add_replay_gain" />
+					<span class="argument">--add-replay-gain</span>
+				</td>
+				<td>
+					Calculates the title and album gains/peaks of the given FLAC files as if all the files were part of one album, then stores them as FLAC tags.  The tags are the same as those used by <span class="commandname">vorbisgain</span>.  Existing ReplayGain tags will be replaced.  If only one FLAC file is given, the album and title gains will be the same.  Since this operation requires two passes, it is always executed last, after all other operations have been completed and written to disk.  All FLAC files specified must have the same resolution, sample rate, and number of channels.  The sample rate must be one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, or 48 kHz.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_add_replay_gain_scan" />
+					<span class="argument">--scan-replay-gain</span>
+				</td>
+				<td>
+					Like <span class="argument">--add-replay-gain</span>, but only analyzes the files rather than writing them to the tags.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_remove_replay_gain" />
+					<span class="argument">--remove-replay-gain</span>
+				</td>
+				<td>
+					Removes the ReplayGain tags.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_add_seekpoint" />
+					<span class="argument">--add-seekpoint={#|X|#x|#s}</span>
+				</td>
+				<td>
+					Add seek points to a <span class="code">SEEKTABLE</span> block:<br />
+					<ul>
+					<li>
+						<span class="argument">#&nbsp;</span> : a specific sample number for a seek point
+					</li>
+					<li>
+						<span class="argument">X&nbsp;</span> : a placeholder point (always goes at the end of the <span class="code">SEEKTABLE</span>)
+					</li>
+					<li>
+						<span class="argument">#x</span> : # evenly spaced seekpoints, the first being at sample 0
+					</li>
+					<li>
+						<span class="argument">#s</span> : a seekpoint every # seconds; # does not have to be a whole number, it can be, for example, <span class="argument">9.5</span>, meaning a seekpoint every 9.5 seconds
+					</li>
+					</ul>
+					If no <span class="code">SEEKTABLE</span> block exists, one will be created.  If one already exists, points will be added to the existing table, and any duplicates will be turned into placeholder points.<br />
+					You may use many <span class="argument">--add-seekpoint</span> options; the resulting <span class="code">SEEKTABLE</span> will be the unique-ified union of all such values.  Example: <span class="argument">--add-seekpoint=100x --add-seekpoint=3.5s</span> will add 100 evenly spaced seekpoints and a seekpoint every 3.5 seconds.<br />
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_shorthand_add_padding" />
+					<span class="argument">--add-padding=#</span>
+				</td>
+				<td>
+					Add a padding block of the given length (in bytes).  The overall length of the new block will be 4 + length; the extra 4 bytes is for the metadata block header.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td colspan="2" bgcolor="#D3D4C5">
+					<a name="major_operations"><font size="+1"><b>Major Operations</b></font></a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_operations_version" />
+					<span class="argument">--version</span>
+				</td>
+				<td>
+					Show the metaflac version number.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_operations_list" />
+					<span class="argument">--list</span>
+				</td>
+				<td>
+					List the contents of one or more metadata blocks to stdout.  By default, all metadata blocks are listed in text format.  Use the following options to change this behavior:<br />
+					<br />
+
+					<span class="argument">--block-number=#[,#[...]]</span><br />
+					An optional comma-separated list of block numbers to display.  The first block, the <span class="code">STREAMINFO</span> block, is block 0.<br />
+					<br />
+
+					<span class="argument">--block-type=type[,type[...]]</span><br />
+					<span class="argument">--except-block-type=type[,type[...]]</span><br />
+					An optional comma-separated list of block types to be included or ignored with this option.  Use only one of <span class="argument">--block-type</span> or <span class="argument">--except-block-type</span>.  The valid block types are: <span class="code">STREAMINFO</span>, <span class="code">PADDING</span>, <span class="code">APPLICATION</span>, <span class="code">SEEKTABLE</span>, <span class="code">VORBIS_COMMENT</span>.  You may narrow down the types of <span class="code">APPLICATION</span> blocks displayed as follows:<br />
+					<table border="1">
+						<tr>
+							<td><span class="argument">APPLICATION:abcd</span></td>
+							<td>The <span class="code">APPLICATION</span> block(s) whose textual representation of the 4-byte ID is "abcd"</td>
+						</tr>
+						<tr>
+							<td><span class="argument">APPLICATION:0xXXXXXXXX</span></td>
+							<td>The <span class="code">APPLICATION</span> block(s) whose hexadecimal big- endian representation of the 4-byte ID is "0xXXXXXXXX".  For the example "abcd" above the hexadecimal equivalalent is 0x61626364</td>
+						</tr>
+					</table>
+					<br />
+
+					NOTE: if both <span class="argument">--block-number</span> and <span class="argument">--[except-]block-type</span> are specified, the result is the logical AND of both arguments.<br />
+					<br />
+
+					<span class="argument">--application-data-format=hexdump|text</span><br />
+					If the application block you are displaying contains binary data but your <span class="argument">--data-format=text</span>, you can display a hex dump of the application data contents instead using <span class="argument">--application-data-format=hexdump</span>.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_operations_remove" />
+					<span class="argument">--remove</span>
+				</td>
+				<td>
+					Remove one or more metadata blocks from the metadata.  Unless <span class="argument">--dont-use-padding</span> is specified, the blocks will be replaced with padding.  You may not remove the <span class="code">STREAMINFO</span> block.<br />
+					<br />
+
+					<span class="argument">--block-number=#[,#[...]]</span><br />
+					<span class="argument">--block-type=type[,type[...]]</span><br />
+					<span class="argument">--except-block-type=type[,type[...]]</span><br />
+					See <a href="#metaflac_operations_list"><span class="argument">--list</span></a> above for usage.<br />
+					<br />
+
+					NOTE: if both <span class="argument">--block-number</span> and <span class="argument">--[except-]block-type</span> are specified, the result is the logical AND of both arguments.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_operations_remove_all" />
+					<span class="argument">--remove-all</span>
+				</td>
+				<td>
+					Remove all metadata blocks (except the <span class="code">STREAMINFO</span> block) from the metadata.  Unless <span class="argument">--dont-use-padding</span> is specified, the blocks will be replaced with padding.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_operations_merge_padding" />
+					<span class="argument">--merge-padding</span>
+				</td>
+				<td>
+					Merge adjacent <span class="code">PADDING</span> blocks into single blocks.
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<a name="metaflac_operations_sort_padding" />
+					<span class="argument">--sort-padding</span>
+				</td>
+				<td>
+					Move all <span class="code">PADDING</span> blocks to the end of the metadata and merge them into a single block.
+				</td>
+			</tr>
+		</table>
+		</td></tr></table>
+
+		<br />
+		<a name="option_index"><font size="+1"><b><u>Option Index</u></b></font></a><br />
+		<br />
+		<a href="#metaflac_shorthand_add_padding"><span class="argument">--add-padding</span></a><br />
+		<a href="#metaflac_shorthand_add_replay_gain"><span class="argument">--add-replay-gain</span></a><br />
+		<a href="#metaflac_shorthand_add_seekpoint"><span class="argument">--add-seekpoint</span></a><br />
+		<a href="#metaflac_options_dont_use_padding"><span class="argument">--dont-use-padding</span></a><br />
+		<a href="#metaflac_shorthand_export_cuesheet_to"><span class="argument">--export-cuesheet-to</span></a><br />
+		<a href="#metaflac_shorthand_export_picture_to"><span class="argument">--export-picture-to</span></a><br />
+		<a href="#metaflac_shorthand_export_tags_to"><span class="argument">--export-tags-to</span></a><br />
+		<a href="#metaflac_shorthand_import_cuesheet_from"><span class="argument">--import-cuesheet-from</span></a><br />
+		<a href="#metaflac_shorthand_import_picture_from"><span class="argument">--import-picture-from</span></a><br />
+		<a href="#metaflac_shorthand_import_tags_from"><span class="argument">--import-tags-from</span></a><br />
+		<a href="#metaflac_operations_list"><span class="argument">--list</span></a><br />
+		<a href="#metaflac_operations_merge_padding"><span class="argument">--merge-padding</span></a><br />
+		<a href="#metaflac_options_no_filename"><span class="argument">--no-filename</span></a><br />
+		<a href="#metaflac_options_no_utf8_convert"><span class="argument">--no-utf8-convert</span></a><br />
+		<a href="#metaflac_options_preserve_modtime"><span class="argument">--preserve-modtime</span></a><br />
+		<a href="#metaflac_shorthand_remove_all_tags"><span class="argument">--remove-all-tags</span></a><br />
+		<a href="#metaflac_operations_remove_all"><span class="argument">--remove-all</span></a><br />
+		<a href="#metaflac_shorthand_remove_first_tag"><span class="argument">--remove-first-tag</span></a><br />
+		<a href="#metaflac_shorthand_remove_replay_gain"><span class="argument">--remove-replay-gain</span></a><br />
+		<a href="#metaflac_shorthand_remove_tag"><span class="argument">--remove-tag</span></a><br />
+		<a href="#metaflac_operations_remove"><span class="argument">--remove</span></a><br />
+		<a href="#metaflac_shorthand_scan_replay_gain"><span class="argument">--scan-replay-gain</span></a><br />
+		<a href="#metaflac_shorthand_set_tag_from_file"><span class="argument">--set-tag-from-file</span></a><br />
+		<a href="#metaflac_shorthand_set_tag"><span class="argument">--set-tag</span></a><br />
+		<a href="#metaflac_shorthand_show_bps"><span class="argument">--show-bps</span></a><br />
+		<a href="#metaflac_shorthand_show_channels"><span class="argument">--show-channels</span></a><br />
+		<a href="#metaflac_shorthand_show_max_blocksize"><span class="argument">--show-max-blocksize</span></a><br />
+		<a href="#metaflac_shorthand_show_max_framesize"><span class="argument">--show-max-framesize</span></a><br />
+		<a href="#metaflac_shorthand_show_md5sum"><span class="argument">--show-md5sum</span></a><br />
+		<a href="#metaflac_shorthand_show_min_blocksize"><span class="argument">--show-min-blocksize</span></a><br />
+		<a href="#metaflac_shorthand_show_min_framesize"><span class="argument">--show-min-framesize</span></a><br />
+		<a href="#metaflac_shorthand_show_sample_rate"><span class="argument">--show-sample-rate</span></a><br />
+		<a href="#metaflac_shorthand_show_tag"><span class="argument">--show-tag</span></a><br />
+		<a href="#metaflac_shorthand_show_total_samples"><span class="argument">--show-total-samples</span></a><br />
+		<a href="#metaflac_shorthand_show_vendor_tag"><span class="argument">--show-vendor-tag</span></a><br />
+		<a href="#metaflac_operations_sort_padding"><span class="argument">--sort-padding</span></a><br />
+		<a href="#metaflac_operations_version"><span class="argument">--version</span></a><br />
+		<a href="#metaflac_options_with_filename"><span class="argument">--with-filename</span></a><br />
+
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/faq.html b/doc/html/faq.html
new file mode 100644
index 0000000..5612002
--- /dev/null
+++ b/doc/html/faq.html
@@ -0,0 +1,390 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--  Copyright (c) 2000-2009  Josh Coalson -->
+<!--  Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - faq</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;faq&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		faq
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		<b>General</b>
+		<ul>
+			<li>
+				<a href="faq.html#general__what_is"><b>What is FLAC?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__how_to"><b>I have a FLAC file, how do I play it?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__how_to"><b>How can I create FLAC files?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__license"><b>What licensing applies to the FLAC format and software?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__tagging"><b>What kinds of tags does FLAC support?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__software"><b>What software support FLAC?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__software_wmp"><b>How can I play FLAC in Windows Media Player?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__hardware"><b>What hardware products support FLAC?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__native_vs_ogg"><b>What is the difference between (native) FLAC and Ogg FLAC?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__native_or_ogg"><b>Which should I use, (native) FLAC or Ogg FLAC?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__no_cuesheet_tags"><b>Why aren't PERFORMER/TITLE/etc tags stored in the FLAC CUESHEET block?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__no_wave_metadata"><b>Why doesn't FLAC store all WAVE metadata?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__not_wave_compressor"><b>If flac compresses WAVE files, why isn't it technically a WAVE file compressor?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__no_riff_subchunks"><b>Why do some lossless comparisons say FLAC does not support RIFF chunks?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__asymmetry"><b>Why do the encoder settings have a big effect on the encoding time but not the decoding time?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__alternatives"><b>Why use FLAC instead of other codecs that compress more?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__encode_faster"><b>Why can't you make FLAC encode faster?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__lossless_trust"><b>How can I be sure FLAC is lossless?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__testing"><b>How much testing has been done on FLAC?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__lowest_bitrate"><b>What is the lowest bitrate (or highest compression) achievable with FLAC?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__channels"><b>How many channels does FLAC support?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__samples"><b>What kind of audio samples does FLAC support?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#general__samples_fp"><b>Will FLAC ever support floating-point samples?</b></a>
+			</li>
+		</ul>
+		<b>Tools</b>
+		<ul>
+			<li>
+				<a href="faq.html#tools__eac_and_flac"><b>How do I set up EAC to rip directly to FLAC?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__runtime75"><b>Why am I getting "Run-time error '75': Path/File access error" with FLAC Frontend?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__option_blocking"><b>How do I encode a file that starts with a dash?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__long_meta_edits"><b>Why does it take so long to edit some FLAC files with metaflac?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__wildcards_on_windows"><b>Why don't wildcards for file names like *.flac or *.wav work with <span class="commandname">flac</span>/<span class="commandname">metaflac</span> on Windows?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__hardware_prob"><b>I compressed a file to FLAC with verify on, and flac said "Verify FAILED!"  Why?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__wave_flac_wave"><b>I compressed a WAVE file to FLAC, then decompressed to WAVE, and the two weren't identical.  Why?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__skipped_subchunk"><b>I compressed a WAVE file to FLAC and it said "warning: skipping unknown sub-chunk LIST".  Why?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__two_bytes_short"><b>I decoded a FLAC file and the WAVE is 2 bytes shorter than the original.  Why?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__not_streamable"><b>Why did I get "ERROR initializing encoder, state = FLAC__STREAM_ENCODER_NOT_STREAMABLE"?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#tools__different_sizes"><b>Why doesn't the same file compressed on different machines with the same options yield the same FLAC file?</b></a>
+			</li>
+		</ul>
+		<b>API</b>
+		<ul>
+			<li>
+				<a href="faq.html#api__release_versioning"><b>Why does your API change for point releases?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#api__frame_length"><b>How can I determine the encoded frame length?</b></a>
+			</li>
+		</ul>
+		<b>Project</b>
+		<ul>
+			<li>
+				<a href="faq.html#project__lists"><b>Where are the mailing lists, forums, discussion areas, etc.?</b></a>
+			</li>
+			<li>
+				<a href="faq.html#project__submit_bug"><b>How do I submit a bug report?</b></a>
+			</li>
+		</ul>
+
+		<h2>
+			<b>General</b>
+		</h2>
+
+		<a name="general__what_is"><b>What is FLAC?</b></a><br />
+		<br />
+		FLAC stands for Free Lossless Audio Codec, an audio format similar to MP3, but lossless, meaning that audio is compressed in FLAC without any loss in quality.  This is similar to how Zip works, except with FLAC you will get much better compression because it is designed specifically for audio, and you can play back compressed FLAC files in your favorite player (or your car or home stereo, see <a href="http://xiph.org/flac/links.html#hardware">supported devices</a>) just like you would an MP3 file.<br />
+		<br />
+		For more details, see <a href="features.html">What is FLAC?</a><br />
+		<br />
+		<a name="general__how_to"><b>I have a FLAC file, how do I play it?</b></a><br />
+		<b>How can I create FLAC files?</b><br />
+		<br />
+		See <a href="http://xiph.org/flac/documentation_tasks.html">Using FLAC</a> or a <a href="http://xiph.org/flac/links.html">list of hardware that supports FLAC</a>.<br />
+		<br />
+		<a name="general__license"><b>What licensing applies to the FLAC format and software?</b></a><br />
+		<br />
+		See the <a href="license.html">license page</a>.<br />
+		<br />
+		<a name="general__tagging"><b>What kinds of tags does FLAC support?</b></a><br />
+		<br />
+		FLAC has it's own native tagging system which is identical to that of Vorbis.  They are called alternately "FLAC tags" and "Vorbis comments".  It is the only tagging system required and guaranteed to be supported by FLAC implementations.<br />
+		<br />
+		Out of convenience, the reference decoder knows how to skip ID3 tags so that they don't interfere with decoding.  But you should not expect any tags beside FLAC tags to be supported in applications; some implementations may not even be able to decode a FLAC file with ID3 tags.<br />
+		<br />
+		<a name="general__software"><b>What software support FLAC?</b></a><br />
+		<br />
+		This list is so large now it is difficult to maintain and keep up-to-date.  For a partial list of open-source software that supports FLAC, see the <a href="http://xiph.org/flac/links.html#software">software section</a> of the links page.  For a partial list of the most popular software used to encode, decode, play, tag, and rip FLAC files, see the <a href="http://xiph.org/flac/download.html">download page</a>.<br />
+		<br />
+		<a name="general__software_wmp"><b>How can I play FLAC in Windows Media Player?</b></a><br />
+		<br />
+		The easiest way is to use the Xiph.org Directshow Filters, <a href="http://www.xiph.org/dshow/downloads/">download them here</a><br />
+		<br />
+		<a name="general__hardware"><b>What hardware products support FLAC?</b></a><br />
+		<br />
+		See the <a href="http://xiph.org/flac/links.html#hardware">hardware section</a> of the links page.<br />
+		<br />
+		<a name="general__native_vs_ogg"><b>What is the difference between (native) FLAC and Ogg FLAC?</b></a><br />
+		<br />
+		You can think of an audio codec as having two layers.  The inside layer is the raw compressed data, and the outside layer is the "container" or "transport layer" that splits and arranges the compressed data in pieces so it can be seeked through, edited, etc.<br />
+		<br />
+		"Native" FLAC is the compressed FLAC data stored in a very minimalist container, designed to be very efficient at storing single audio streams.<br />
+		<br />
+		Ogg FLAC is the compressed FLAC data stored in an <a href="http://xiph.org/vorbis/doc/oggstream.html">Ogg container</a>.  Ogg is a much more powerful transport layer that enables mixing several kinds of different streams (audio, data, metadata, etc).  The overhead is slightly higher than with native FLAC.<br />
+		<br />
+		In either case, the compressed FLAC data is the same and one can be converted to the other without re-encoding.<br />
+		<br />
+		<a name="general__native_or_ogg"><b>Which should I use, (native) FLAC or Ogg FLAC?</b></a><br />
+		<br />
+		The short answer right now is probably "native FLAC".  If all you are doing is compressing audio to be played back later, native FLAC will do everything you need, is more widely supported, and will yield smaller files.  If you plan to edit the compressed audio, or want to multiplex the audio with video later in an Ogg container, Ogg FLAC is a better choice.<br />
+		<br />
+		<a name="general__no_cuesheet_tags"><b>Why aren't PERFORMER/TITLE/etc tags stored in the FLAC CUESHEET block?</b></a><br />
+		<br />
+		This has turned out to be a pretty polarizing issue and requires a long explanation.<br />
+		<br />
+		The original purpose of a cue sheet in CD authoring software was to lay out the disc, essentially specifying how the audio will be organized on the disc; some of the information ends up as the CD table of contents: the track numbers and locations, and the index points.  Later CD-TEXT was added.  But CD-TEXT is a very complex spec, and actually goes in the CD subcode data.  It is internationalized, not through Unicode, but with several different character sets, some of them multi-byte.  It even allows for graphics.  In cue sheets, the TITLE/PERFORMER/etc tags are just a limited shorthand for authoring CD-TEXT, but when you rip, you almost never parse the CD-TEXT, you get it from another database, and it doesn't really belong in the FLAC CUESHEET block.<br />
+		<br />
+		For FLAC the intention is that applications can calculate the CDDB or CDindex ID from the CUESHEET block and look it up in an online or local database just like CD rippers and players do.  But if you really want it in the file itself, the track metadata should be stored separate from the CUESHEET, and already can be because of FLAC's metadata system.  There just isn't a method specified yet because as soon as it is, people will say that it's not flexible enough.  From experience (and you can see this come up time and time again in many lists), anyone who is going to the trouble of keeping a lossless collection in the first place will already be picky about metadata, and it is hard to come up with a standard that will please even the majority.  That is the big problem with metadata and is why Xiph has deferred on it, waiting for someone to come up with a good metadata spec that can be multiplexed together with data.<br />
+		<br />
+		Some players (for example Foobar2000) allow you to store the CDDB data as FLAC tags and can parse that.<br />
+		<br />
+		<a name="general__no_wave_metadata"><b>Why doesn't FLAC store all WAVE metadata?</b></a><br />
+		<a name="general__not_wave_compressor"><b>If flac compresses WAVE files, why isn't it technically a WAVE file compressor?</b></a><br />
+		<br />
+		(By default, <span class="commandname">flac</span> does not store WAVE metadata, but it can with the <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> option described below.)<br />
+		<br />
+		FLAC is a general-purpose audio format, not just a compressed WAVE file format.  There's a subtle difference.  WAVE is a complicated standard; many kinds of data besides audio data can be put in it.  FLAC's purpose is not to reproduce a WAVE file, including all the non-audio data that is in it, it is to losslessly compress the audio.<br />
+		<br />
+		However, if you really need to store the non-audio parts of a WAVE or AIFF file, you can use the <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> option to <span class="commandname">flac</span> when encoding to store it in FLAC metadata, then use the option again when decoding to restore in to the decoded WAVE/AIFF file.<br />
+		<br />
+		<a name="general__no_riff_subchunks"><b>Why do some lossless comparisons say FLAC does not support RIFF chunks?</b></a><br />
+		<br />
+		This is a limitation that no longer exists with FLAC (<a href="faq.html#general__no_wave_metadata">see above</a>).<br />
+		<br />
+		<a name="general__asymmetry"><b>Why do the encoder settings have a big effect on the encoding time but not the decoding time?</b></a><br />
+		<br />
+		It's hard to explain without going into the codec design, but to oversimplify, the encoder is looking for functions that approximate the signal.  Higher settings make the encoder search more to find better approximations.  The functions are themselves encoded in the FLAC file.  Decoding only requires computing the one chosen function, and the complexity of the function is very stable.  This is by design, to make decoding easier, and is one of the things that makes FLAC easy to implement in hardware.<br />
+		<br />
+		<a name="general__alternatives"><b>Why use FLAC instead of other codecs that compress more?</b></a><br />
+		<br />
+		For most users, a small difference in filesize is usually far outweighed by FLAC's advantages: open patent free codec, portable open source (BSD) reference implementation, documented API, multi-platform support, hardware support, multi-channel support, etc.  Improving FLAC to get a little more compression is not worth making it more complex and more compute-intensive to decode, and hence, less likely to be supported in hardware.<br />
+		<br />
+		<a name="general__encode_faster"><b>Why can't you make FLAC encode faster?</b></a><br />
+		<br />
+		FLAC already encodes pretty fast.  It is faster than real-time even on weak systems and is not much slower than even the fastest codecs.  And it is faster than the CD ripping process with which it is usually paired, meaning even if it went faster, it would not speed up the ripping-encoding process anyway.<br />
+		<br />
+		Part of the reason is that FLAC is asymmetric <a href="faq.html#general__asymmetry">(see also)</a>.  That means that it is optimized for decoding speed at the expense of encoding speed, because it makes it easier to decode on low-powered hardware, and because you only encode once but you decode many times.  <br />
+		<br />
+		<a name="general__lossless_trust"><b>How can I be sure FLAC is lossless?</b></a><br />
+		<a name="general__testing"><b>How much testing has been done on FLAC?</b></a><br />
+		<br />
+		First, FLAC is probably the only lossless compressor that has a published and comprehensive test suite.  With the others you rely on the author's personal testing or the longevity of the program.  But with FLAC you can download the whole test suite and run it on any version you like, or alter it to test your own data.  The test suite checks every function in the API, as well as running many thousands of streams through an encode-decode-verify process, to test every nook and cranny of the system.  Even on a fast machine the full test suite takes hours.  The full test suite must pass on several platforms before a release is made.<br />
+		<br />
+		Second, you can always use the <span class="argument">-V</span> option with <span class="commandname">flac</span> (also supported by most GUI frontends) to verify while encoding.  With this option, a decoder is run in parallel to the encoder and its output is compared against the original input.  If a difference is found <span class="commandname">flac</span> will stop with an error.<br />
+		<br />
+		Finally, FLAC is used by many people and has been judged stable enough by many software and hardware makers to be incorporated into their products.<br />
+		<br />
+		<a name="general__lowest_bitrate"><b>What is the lowest bitrate (or highest compression) achievable with FLAC?</b></a><br />
+		<br />
+		With FLAC you do not specify a bitrate like with some lossy codecs.  It's more like specifying a quality with Vorbis or MPC, except with FLAC the quality is always "lossless" and the resulting bitrate is roughly proportional to the amount of information in the original signal.  You cannot control the bitrate much and the result can be from around 100% of the input rate (if you are encoding noise), down to almost 0 (encoding silence).<br />
+		<br />
+		<a name="general__channels"><b>How many channels does FLAC support?</b></a><br />
+		<br />
+		FLAC supports from 1 to 8 channels per stream.  Channels are only grouped in FLAC to take advantage of interchannel correlation and to define common channel assignments (like stereo L/R, 5.1 surround, et cetera).  When encoding a large number of independent channels it is expected that they are coded separately and if required, multiplexed together in a suitable container like Ogg or Matroska.<br />
+		<br />
+		<a name="general__samples"><b>What kind of audio samples does FLAC support?</b></a><br />
+		<br />
+		FLAC supports linear PCM samples with a resolution between 4 and 32 bits per sample.  FLAC does not support floating point samples.  In some cases it is possible to losslessly transform samples from an incompatible range to a FLAC-compatible range before encoding.<br />
+		<br />
+		FLAC supports linear sample rates from 1Hz - 655350Hz in 1Hz increments.<br />
+		<br />
+		<a name="general__samples_fp"><b>Will FLAC ever support floating-point samples?</b></a><br />
+		<br />
+		It's unlikely FLAC will ever support floating-point samples natively.  The main application for floating-point is audio engineering, which demands easy editing and very high speed for both encoding and decoding above everything else.<br />
+		<br />
+		FLAC is designed as a consumer audio format.  It trades ease of editing for a featureful, robust transport layer more suited for playback, and encoding speed for more compression and faster decompression.
+
+		<h2>
+			<b>Tools</b>
+		</h2>
+
+		<a name="tools__eac_and_flac"><b>How do I set up EAC to rip directly to FLAC?</b></a><br />
+		<br />
+		See Case's excellent <a href="http://www.saunalahti.fi/cse/EAC/index.html">EAC configuration page</a>.  Or use <a href="http://www.legroom.net/software/autoflac">AutoFLAC</a> or <a href="http://mareo.netfirms.com/">MAREO</a> to rip to FLAC or multiple formats at once.<br />
+		<br />
+		<a name="tools__runtime75"><b>Why am I getting "Run-time error '75': Path/File access error" with FLAC Frontend?</b></a><br />
+		<br />
+		You are probably using an old version of FLAC Frontend. Try downloading a new version from <a href="http://flacfrontend.sf.net/">this sourceforge page</a><br />
+		<br />
+		<a name="tools__option_blocking"><b>How do I encode a file that starts with a dash?</b></a><br />
+		<br />
+		When using <span class="commandname">flac</span> to encode on the command-line, a file that starts with a dash will be treated as an option, but there is a simple workaround.  Use <span class="argument">--</span> to signal the end of options and the beginning of filenames, like so:<br />
+		<br />
+		<span class="code">flac -V -- -01-name.wav</span><br />
+		<br />
+		<a name="tools__long_meta_edits"><b>Why does it take so long to edit some FLAC files with metaflac?</b></a><br />
+		<br />
+		Since metadata is stored at the beginning of a FLAC file, changing the length of it can sometimes cause the whole file to be rewritten.  You can avoid this by adding padding with <span class="commandname">flac</span> when you encode, or with <span class="commandname">metaflac</span> after encoding.  By default, <span class="commandname">flac</span> adds 8k of padding; you can change this amount if you need more or less.<br />
+		<br />
+		<a name="tools__wildcards_on_windows"><b>Why don't wildcards for file names like *.flac or *.wav work with <span class="commandname">flac</span>/<span class="commandname">metaflac</span> on Windows?</b></a><br />
+		<br />
+		The Windows command shells (cmd.exe, command.com) implement wildcard handling differently than most other shells, leaving it up to the program to do everything including difficult and ambiguous cases.  For an explanation of why wildcards on cmd.exe/command.com are dangerous, see <a href="http://www.hydrogenaud.io/forums/index.php?showtopic=50667&amp;st=75&amp;p=466078&amp;#entry466078">here</a>.  Better command shells for Windows exist, e.g. from <a href="http://cygwin.com/">Cygwin</a>.  A workaround with the Windows shells is to do something like:<br />
+		<br />
+		<tt>for %F in (*.wav) do flac "%F"</tt><br />
+		<br />
+		but care must still be taken that the command will execute as intended.<br />
+		<br />
+		<a name="tools__hardware_prob"><b>I compressed a file to FLAC with verify on, and flac said "Verify FAILED!"  Why?</b></a><br />
+		<br />
+		The only known cause of verify errors is faulty hardware.  The dead giveaway is that if you repeat the exact same command, the error occurs in a different place or not at all.  This can also happen when decoding or testing a FLAC file.  If this is happening it is your hardware and not a FLAC bug.<br />
+		<br />
+		The problem is usually caused by overclocking/overheating the CPU or bad RAM.  Try one of the many free programs available for testing hardware (e.g. <a href="http://www.memtest.org/">Memtest</a>).<br />
+		<br />
+		If you ever have a verify error that fails at the same place every time, please <a href="faq.html#project__submit_bug">file a bug</a>, uploading a sample according to <a href="http://sourceforge.net/p/flac/bugs/42/">the instructions found at the bottom of this bug report</a>.<br />
+		<br />
+		<a name="tools__wave_flac_wave"><b>I compressed a WAVE file to FLAC, then decompressed to WAVE, and the two weren't identical.  Why?</b></a><br />
+		<a name="tools__skipped_subchunk"><b>I compressed a WAVE file to FLAC and it said "warning: skipping unknown sub-chunk LIST".  Why?</b></a><br />
+		<br />
+		WAVE is a complicated standard; many kinds of data besides audio data can be put in it.  Most likely what has happened is that the application that created the original WAVE file also added some extra information for it's own use, which FLAC does not store or recreate by default (but can with the <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> option) (<a href="faq.html#tools__two_bytes_short">see also</a>).  The audio data in the two WAVE files will be identical.  There are other tools to compare just the audio content of two WAVE files; <a href="http://www.exactaudiocopy.de/">ExactAudioCopy</a> has such a feature.<br />
+		<br />
+		For the more technically inclined, by default FLAC only stores what is in the 'fmt ' and 'data' sub-chunks of a WAVE file.  <a href="faq.html#general__no_wave_metadata">(see also)</a><br />
+		<br />
+		<a name="tools__two_bytes_short"><b>I decoded a FLAC file and the WAVE is 2 bytes shorter than the original.  Why?</b></a><br />
+		<br />
+		The difference is probably that between an 18-byte 'fmt ' subchunk in the original WAVE vs. a 16-byte one in the decoded WAVE.  With WAVE there is more than one way to write identical formatting information, but FLAC always writes the most common legal form.  <a href="faq.html#tools__wave_flac_wave">(see also)</a><br />
+		<br />
+		<a name="tools__not_streamable"><b>Why did I get "ERROR initializing encoder, state = FLAC__STREAM_ENCODER_NOT_STREAMABLE"?</b></a><br />
+		<br />
+		You specified encoding options that are outside the <a href="format.html#subset">Streamable subset</a>.  If that is what you really wanted and you understand the consequences, you can use <span class="code">flac --lax</span> to generate a non-Subset stream.  The resulting file may not be streamable or play in all players.<br />
+		<br />
+		<a name="tools__different_sizes"><b>Why doesn't the same file compressed on different machines with the same options yield the same FLAC file?</b></a><br />
+		<br />
+		It's not supposed to, and neither does it mean either encoding was bad.  There are many variations between different machines or even different builds of <span class="commandname">flac</span> on the same machine that can lead to small differences in the FLAC file, even if they have the exact same final size.  This is normal.
+
+		<h2>
+			<b>API</b>
+		</h2>
+
+		<a name="api__release_versioning"><b>Why does your API change for point releases?</b></a><br />
+		<br />
+		The FLAC release numbering scheme of MAJOR.MINOR.MICRO reflects the state of the FLAC format, not the API.  This is most intuitive for users, at the expense of flustering developers.  The shared library number (derived from the libtool current:revision:age number) is the indicator of binary API compatibility.  As of FLAC 1.1.3, the current, revision, and age numbers are also <tt>#define</tt>d in the library headers to make porting easier; see the <a href="api/group__porting.html">porting guide</a>.<br />
+		<br />
+		<a name="api__frame_length"><b>How can I determine the encoded frame length?</b></a><br />
+		<br />
+		With native FLAC, it is not possible to determine the frame length without decoding.  Probably if I had it all to do again I would have constrained the possible block sizes, which would have made it more practical to put the frame length in the frame header.  For an example of how to find the frame boundaries in a stream, see the source code to <span class="commandname">metaflac</span>, in the functionality that adds seek points.<br />
+		<br />
+		With Ogg FLAC, it can be calculated from the Ogg page header.
+
+		<h2>
+			<b>Project</b>
+		</h2>
+
+		<a name="project__lists"><b>Where are the mailing lists, forums, discussion areas, etc.?</b></a><br />
+		<br />
+		There are a few places.  The main discussions happen on <a href="http://lists.xiph.org/mailman/listinfo">the official FLAC mailing lists</a> (you must subscribe to post).  Also, there is a lot of discussion relating to FLAC on <a href="http://www.hydrogenaud.io/">Hydrogen Audio</a>.<br />
+		<br />
+		<a name="project__submit_bug"><b>How do I submit a bug report?</b></a><br />
+		<br />
+		First, <a href="http://sourceforge.net/p/flac/bugs/">visit the bug tracking page</a> and do a little searching of both open and closed bugs to see if yours is already there.  If you have something truly new submit a new bug there.  <b>Make sure</b> to monitor the bug or include your email address in the description.  Include as much information as possible: the version of FLAC that you are running, the name and version of any frontend you are running, your operating system and version, your CPU type and speed, the amount of memory you have, where you downloaded FLAC from, the exact error message (if any) copied from the console, and anything else you may think will help.
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/favicon.ico b/doc/html/favicon.ico
new file mode 100644
index 0000000..594fe38
--- /dev/null
+++ b/doc/html/favicon.ico
Binary files differ
diff --git a/doc/html/features.html b/doc/html/features.html
new file mode 100644
index 0000000..1e87287
--- /dev/null
+++ b/doc/html/features.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - features</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		<a name="introduction">introduction</a>
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		FLAC stands for Free Lossless Audio Codec, an audio format similar to MP3, but lossless, meaning that audio is compressed in FLAC without any loss in quality.  This is similar to how Zip works, except with FLAC you will get much better compression because it is designed specifically for audio, and you can play back compressed FLAC files in your favorite player (or your car or home stereo, see <a href="http://xiph.org/flac/links.html#hardware">supported devices</a>) just like you would an MP3 file.<br />
+		<br />
+		FLAC stands out as the <a href="http://xiph.org/flac/comparison.html">fastest and most widely supported lossless audio codec</a>, and the only one that at once is non-proprietary, is unencumbered by patents, has an open-source reference implementation, has a well documented format and API, and has several other independent implementations.<br />
+		<br />
+		FLAC supports tagging, cover art, and fast seeking.  FLAC is freely available and supported on most operating systems, including Windows, "unix" (Linux, *BSD, Solaris, OS X, IRIX), BeOS, OS/2, and Amiga.<br />
+		<br />
+		There are <a href="http://xiph.org/flac/links.html">many programs and devices that support FLAC</a>, but the core FLAC project here maintains the format and provides <a href="documentation_tools.html">programs</a> and <a href="developers.html">libraries</a> for working with FLAC files.  See <a href="http://xiph.org/flac/download.html">Getting FLAC</a> for instructions on downloading and installing the official FLAC tools, or <a href="http://xiph.org/flac/documentation_tasks.html">Using FLAC</a> for instructions and guides on playing FLAC files, ripping CDs to FLAC, etc.<br />
+		<br />
+		When we say that FLAC is "Free" it means more than just that it is available at no cost.  It means that the specification of the format is fully open to the public to be used for any purpose (the FLAC project reserves the right to set the FLAC specification and certify compliance), and that neither the FLAC format nor any of the implemented encoding/decoding methods are covered by any known patent.  It also means that all the source code is available under open-source licenses.  It is the first truly open and free lossless audio format.  (For more information, see the <a href="license.html">license page</a>.)<br />
+		<br />
+		Notable features of FLAC:
+		<ul>
+			<li>
+				<b>Lossless</b>: The encoding of audio (PCM) data incurs no loss of information, and the decoded audio is bit-for-bit identical to what went into the encoder.  Each frame contains a 16-bit CRC of the frame data for detecting transmission errors.  The integrity of the audio data is further insured by storing an <a href="http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html">MD5 signature</a> of the original unencoded audio data in the file header, which can be compared against later during decoding or testing.
+			</li>
+			<li>
+				<b>Fast</b>: FLAC is asymmetric in favor of decode speed.  Decoding requires only integer arithmetic, and is much less compute-intensive than for most perceptual codecs.  Real-time decode performance is easily achievable on even modest hardware.
+			</li>
+			<li>
+				<b>Hardware support</b>: FLAC is supported by <a href="http://xiph.org/flac/links.html#hardware">dozens of consumer electronic devices</a>, from portable players, to home stereo equipment, to car stereo.
+			</li>
+			<li>
+				<b>Flexible metadata</b>: FLAC's metadata system supports tags, cover art, seek tables, and cue sheets.  Applications can write their own <a href="format.html#def_APPLICATION">APPLICATION</a> metadata once they <a href="id.html">register an ID</a>.  New metadata blocks can be defined and implemented in future versions of FLAC without breaking older streams or decoders.
+			</li>
+			<li>
+				<b>Seekable</b>: FLAC supports fast sample-accurate seeking.  Not only is this useful for playback, it makes FLAC files suitable for use in editing applications.
+			</li>
+			<li>
+				<b>Streamable</b>: Each FLAC frame contains enough data to decode that frame.  FLAC does not even rely on previous or following frames.  FLAC uses sync codes and CRCs (similar to MPEG and other formats), which, along with framing, allow decoders to pick up in the middle of a stream with a minimum of delay.
+			</li>
+			<li>
+				<b>Suitable for archiving</b>: FLAC is an open format, and there is no generation loss if you need to convert your data to another format in the future.  In addition to the frame CRCs and MD5 signature, <span class="commandname">flac</span> has a verify option that decodes the encoded stream in parallel with the encoding process and compares the result to the original, aborting with an error if there is a mismatch.
+			</li>
+			<li>
+				<b>Convenient CD archiving</b>: FLAC has a <a href="format.html#def_CUESHEET">"cue sheet"</a> metadata block for storing a CD table of contents and all track and index points.  For instance, you can rip a CD to a single file, then import the CD's extracted cue sheet while encoding to yield a single file representation of the entire CD.  If your original CD is damaged, the cue sheet can be exported later in order to burn an exact copy.
+			</li>
+			<li>
+				<b>Error resistant</b>: Because of FLAC's framing, stream errors limit the damage to the frame in which the error occurred, typically a small fraction of a second worth of data.  Contrast this with some other lossless codecs, in which a single error destroys the remainder of the stream.
+			</li>
+		</ul>
+		What FLAC is <b>not</b>:
+		<ul>
+			<li>
+				Lossy.  FLAC is intended for lossless compression only, as there are many good lossy formats already, such as <a href="http://xiph.org/vorbis">Vorbis</a>, <a href="http://www.musepack.net/">MPC</a>, and <a href="http://www.mp3-tech.org/">MP3</a> (see <a href="http://lame.sourceforge.net/">LAME</a> for an excellent open-source implementation).
+			</li>
+			<li>
+				DRM.  There is no intention to add any copy prevention methods.  Of course, we can't stop someone from encrypting a FLAC stream in another container (e.g. the way Apple encrypts AAC in MP4 with FairPlay), that is the choice of the user.
+			</li>
+		</ul>
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/flac.css b/doc/html/flac.css
new file mode 100644
index 0000000..a4e5792
--- /dev/null
+++ b/doc/html/flac.css
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c)  2005,2006,2007  Josh Coalson
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.1
+ * or any later version published by the Free Software Foundation;
+ * with no invariant sections.
+ * A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html
+ */
+
+body
+{
+	background-color: #9a9;
+	color: black;
+	margin: 0 auto;
+	padding: 0px;
+	max-width: 1200px;
+}
+
+/*div
+{
+	background-color: #99CC99;
+	margin: 0px;
+	padding: 0px;
+}*/
+
+div.logo
+{
+	background-color: black;
+	padding: 1px;
+	text-align: center;
+}
+
+div.navbar
+{
+	border-width: 2px 0px 2px 0px;
+	border-style: solid;
+	border-color: black;
+	background-color: #D3D4C5;
+	padding: 3px;
+	text-align: center;
+}
+
+
+div.above_nav
+{
+	height: 25px;
+}
+
+div.below_nav
+{
+	height: 25px;
+}
+
+div.body_with_sidebar
+{
+/*	text-align: left; */
+}
+
+div.box
+{
+	text-align: left;
+	margin: 0;
+	background-color: #EEEED4;
+}
+
+div.box_title
+{
+	border-width: 1px 0px 0px 0px;
+	border-style: solid;
+	border-color: black;
+	background-color: #D3D4C5;
+	padding: 3px 6px;
+	font-family: lucida, verdana, helvetica, arial, sans-serif;
+	font-weight: bold;
+	font-size: 150%;
+}
+
+div.box_header
+{
+	border-width: 1px 0px 0px 0px;
+	border-style: solid;
+	border-color: black;
+	background-color: #EEEED4;
+	padding: 3px;
+}
+
+div.box_footer
+{
+	border-width: 0px 0px 1px 0px;
+	border-style: solid;
+	border-color: black;
+	background-color: #EEEED4;
+	padding: 3px;
+}
+
+div.box_body
+{
+	background-color: #EEEED4;
+	padding: 0px 6px;
+	font-family: lucida, verdana, helvetica, arial, sans-serif;
+	font-weight: normal;
+	font-size: 100%;
+}
+
+#newsbox h3
+{
+	margin: 5px 0 0 0;
+	font-size: 0.9em;
+}
+
+#newsbox p
+{
+	margin: 0;
+}
+
+div.smallbox
+{
+	text-align: left;
+	margin: 0 0 0 8px;
+	background-color: #EEEED4;
+}
+
+div.smallbox_title
+{
+	text-align: center;
+	border-width: 1px 0px 0px 0px;
+	border-style: solid;
+	border-color: black;
+	background-color: #D3D4C5;
+	padding: 3px;
+	font-family: lucida, verdana, helvetica, arial, sans-serif;
+	font-weight: bold;
+	font-size: 100%;
+}
+
+div.smallbox_header
+{
+	border-width: 1px 0px 0px 0px;
+	border-style: solid;
+	border-color: black;
+	background-color: #EEEED4;
+	padding: 3px;
+}
+
+div.smallbox_footer
+{
+	border-width: 0px 0px 1px 0px;
+	border-style: solid;
+	border-color: black;
+	background-color: #EEEED4;
+	padding: 3px;
+}
+
+div.smallbox_body
+{
+	background-color: #EEEED4;
+	padding: 0px 3px 0px 3px;
+	font-family: lucida, verdana, helvetica, arial, sans-serif;
+	font-weight: normal;
+	font-size: 80%;
+}
+
+div.copyright
+{
+	text-align: left;
+	margin: 10px;
+}
+
+span.commandname
+{
+	font-family: monospace;
+	font-weight: bold;
+}
+
+span.command
+{
+	font-family: monospace;
+	font-weight: bold;
+}
+
+span.argument
+{
+	font-family: monospace;
+}
+
+span.code
+{
+	font-family: monospace;
+}
+
+a:link    {color:#336699; background-color:transparent}
+a:visited {color:#336699; background-color:transparent}
+a:active  {color:#336699; background-color:transparent}
+a:hover   {color:#336699; background-color:transparent}
diff --git a/doc/html/format.html b/doc/html/format.html
new file mode 100644
index 0000000..ce1e483
--- /dev/null
+++ b/doc/html/format.html
@@ -0,0 +1,1849 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - format</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		format
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		This is a detailed description of the FLAC format.  There is also a companion document that describes <a href="ogg_mapping.html">FLAC-to-Ogg mapping</a>.<br />
+		<br />
+		For a user-oriented overview, see <a href="documentation_format_overview.html">About the FLAC Format</a>.<br />
+		<br />
+		<a name="toc"><font size="+1"><b><u>Table of Contents</u></b></font></a>
+		<ul>
+			<li><a href="#acknowledgments">Acknowledgments</a></li>
+			<li><a href="#scope">Scope</a></li>
+			<li><a href="#architecture">Architecture</a></li>
+			<li><a href="#definitions">Definitions</a></li>
+			<li><a href="#blocking">Blocking</a></li>
+			<li><a href="#interchannel">Interchannel Decorrelation</a></li>
+			<li><a href="#prediction">Prediction</a></li>
+			<li><a href="#residualcoding">Residual Coding</a></li>
+			<li><a href="#format_overview">Format</a></li>
+			<li><a href="#subset">FLAC Subset</a></li>
+			<li>Specification
+				<ul>
+					<li><a href="#stream">STREAM</a>
+						<ul>
+							<li><a href="#metadata_block">METADATA_BLOCK</a>
+								<ul>
+									<li><a href="#metadata_block_header">METADATA_BLOCK_HEADER</a></li>
+									<li><a href="#metadata_block_data">METADATA_BLOCK_DATA</a>
+										<ul>
+											<li><a href="#metadata_block_streaminfo">METADATA_BLOCK_STREAMINFO</a></li>
+											<li><a href="#metadata_block_padding">METADATA_BLOCK_PADDING</a></li>
+											<li><a href="#metadata_block_application">METADATA_BLOCK_APPLICATION</a></li>
+											<li><a href="#metadata_block_seektable">METADATA_BLOCK_SEEKTABLE</a>
+												<ul>
+													<li><a href="#seekpoint">SEEKPOINT</a></li>
+												</ul>
+											</li>
+											<li><a href="#metadata_block_vorbis_comment">METADATA_BLOCK_VORBIS_COMMENT</a></li>
+											<li><a href="#metadata_block_cuesheet">METADATA_BLOCK_CUESHEET</a>
+												<ul>
+													<li><a href="#cuesheet_track">CUESHEET_TRACK</a>
+														<ul>
+															<li><a href="#cuesheet_track_index">CUESHEET_TRACK_INDEX</a></li>
+														</ul>
+													</li>
+												</ul>
+											</li>
+											<li><a href="#metadata_block_picture">METADATA_BLOCK_PICTURE</a></li>
+										</ul>
+									</li>
+								</ul>
+							</li>
+						</ul>
+					</li>
+					<li>
+						<ul>
+							<li><a href="#frame">FRAME</a>
+								<ul>
+									<li><a href="#frame_header">FRAME_HEADER</a></li>
+									<li><a href="#frame_footer">FRAME_FOOTER</a></li>
+									<li><a href="#subframe">SUBFRAME</a>
+										<ul>
+											<li><a href="#subframe_header">SUBFRAME_HEADER</a></li>
+											<li><a href="#subframe_constant">SUBFRAME_CONSTANT</a></li>
+											<li><a href="#subframe_fixed">SUBFRAME_FIXED</a></li>
+											<li><a href="#subframe_lpc">SUBFRAME_LPC</a></li>
+											<li><a href="#subframe_verbatim">SUBFRAME_VERBATIM</a>
+												<ul>
+													<li><a href="#residual">RESIDUAL</a>
+														<ul>
+															<li><a href="#partitioned_rice">RESIDUAL_CODING_METHOD_PARTITIONED_RICE</a>
+																<ul>
+																	<li><a href="#rice_partition">RICE_PARTITION</a></li>
+																</ul>
+															</li>
+															<li><a href="#partitioned_rice2">RESIDUAL_CODING_METHOD_PARTITIONED_RICE2</a>
+																<ul>
+																	<li><a href="#rice2_partition">RICE2_PARTITION</a></li>
+																</ul>
+															</li>
+														</ul>
+													</li>
+												</ul>
+											</li>
+										</ul>
+									</li>
+								</ul>
+							</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+		</ul>
+		<a name="acknowledgments"><font size="+1"><b><u>Acknowledgments</u></b></font></a><br />
+		<br />
+		FLAC owes much to the many people who have advanced the audio compression field so freely.  For instance:
+		<ul>
+			<li>
+				<a href="http://svr-www.eng.cam.ac.uk/~ajr/">A. J. Robinson</a> for his work on <a href="http://svr-www.eng.cam.ac.uk/reports/abstracts/robinson_tr156.html">Shorten</a>; his paper is a good starting point on some of the basic methods used by FLAC.  FLAC trivially extends and improves the fixed predictors, LPC coefficient quantization, and Rice coding used in Shorten.
+			</li>
+			<li>
+				<a href="https://web.archive.org/web/20040215005354/http://csi.usc.edu/faculty/golomb.html">S. W. Golomb</a> and Robert F. Rice; their universal codes are used by FLAC's entropy coder.
+			</li>
+			<li>
+				N. Levinson and J. Durbin; the reference encoder uses an algorithm developed and refined by them for determining the LPC coefficients from the autocorrelation coefficients.
+			</li>
+			<li>
+				And of course, <a href="http://en.wikipedia.org/wiki/Claude_Shannon">Claude Shannon</a>
+			</li>
+		</ul>
+		<a name="scope"><font size="+1"><b><u>Scope</u></b></font></a><br />
+		<br />
+		It is a known fact that no algorithm can losslessly compress all possible input, so most compressors restrict themselves to a useful domain and try to work as well as possible within that domain.  FLAC's domain is audio data.  Though it can losslessly <b>code</b> any input, only certain kinds of input will get smaller.  FLAC exploits the fact that audio data typically has a high degree of sample-to-sample correlation.<br />
+		<br />
+		Within the audio domain, there are many possible subdomains.  For example: low bitrate speech, high-bitrate multi-channel music, etc.  FLAC itself does not target a specific subdomain but many of the default parameters of the reference encoder are tuned to CD-quality music data (i.e. 44.1kHz, 2 channel, 16 bits per sample).  The effect of the encoding parameters on different kinds of audio data will be examined later.<br />
+		<br />
+		<a name="architecture"><font size="+1"><b><u>Architecture</u></b></font></a><br />
+		<br />
+		Similar to many audio coders, a FLAC encoder has the following stages:
+		<ul>
+			<li>
+				<a href="#blocking">Blocking</a>.  The input is broken up into many contiguous blocks.  With FLAC, the blocks may vary in size.  The optimal size of the block is usually affected by many factors, including the sample rate, spectral characteristics over time, etc.  Though FLAC allows the block size to vary within a stream, the reference encoder uses a fixed block size.
+			</li>
+			<li>
+				<a href="#interchannel">Interchannel Decorrelation</a>.  In the case of stereo streams, the encoder will create mid and side signals based on the average and difference (respectively) of the left and right channels.  The encoder will then pass the best form of the signal to the next stage.
+			</li>
+			<li>
+				<a href="#prediction">Prediction</a>.  The block is passed through a prediction stage where the encoder tries to find a mathematical description (usually an approximate one) of the signal.  This description is typically much smaller than the raw signal itself.  Since the methods of prediction are known to both the encoder and decoder, only the parameters of the predictor need be included in the compressed stream.  FLAC currently uses four different classes of predictors (described in the <a href="#prediction">prediction</a> section), but the format has reserved space for additional methods.  FLAC allows the class of predictor to change from block to block, or even within the channels of a block.
+			</li>
+			<li>
+				<a href="#residualcoding">Residual coding</a>.  If the predictor does not describe the signal exactly, the difference between the original signal and the predicted signal (called the error or residual signal) must be coded losslessy.  If the predictor is effective, the residual signal will require fewer bits per sample than the original signal.  FLAC currently uses only one method for encoding the residual (see the <a href="#residualcoding">Residual coding</a> section), but the format has reserved space for additional methods.  FLAC allows the residual coding method to change from block to block, or even within the channels of a block.
+			</li>
+		</ul>
+		In addition, FLAC specifies a metadata system, which allows arbitrary information about the stream to be included at the beginning of the stream.<br />
+		<br />
+		<a name="definitions"><font size="+1"><b><u>Definitions</u></b></font></a><br />
+		<br />
+		Many terms like "block" and "frame" are used to mean different things in different encoding schemes.  For example, a frame in MP3 corresponds to many samples across several channels, whereas an S/PDIF frame represents just one sample for each channel.  The definitions we use for FLAC follow.  Note that when we talk about blocks and subblocks we are referring to the raw unencoded audio data that is the input to the encoder, and when we talk about frames and subframes, we are referring to the FLAC-encoded data.
+		<ul>
+			<li>
+				<b>Block</b>: One or more audio samples that span several channels.
+			</li>
+			<li>
+				<b>Subblock</b>: One or more audio samples within a channel.  So a block contains one subblock for each channel, and all subblocks contain the same number of samples.
+			</li>
+			<li>
+				<b>Blocksize</b>: The number of samples in any of a block's subblocks.  For example, a one second block sampled at 44.1KHz has a blocksize of 44100, regardless of the number of channels.
+			</li>
+			<li>
+				<b>Frame</b>: A frame header plus one or more subframes.
+			</li>
+			<li>
+				<b>Subframe</b>: A subframe header plus one or more encoded samples from a given channel.  All subframes within a frame will contain the same number of samples.
+			</li>
+		</ul>
+		<a name="blocking"><font size="+1"><b><u>Blocking</u></b></font></a><br />
+		<br />
+		The size used for blocking the audio data has a direct effect on the compression ratio.  If the block size is too small, the resulting large number of frames mean that excess bits will be wasted on frame headers.  If the block size is too large, the characteristics of the signal may vary so much that the encoder will be unable to find a good predictor.  In order to simplify encoder/decoder design, FLAC imposes a minimum block size of 16 samples, and a maximum block size of 65535 samples.  This range covers the optimal size for all of the audio data FLAC supports.<br />
+		<br />
+		Currently the reference encoder uses a fixed block size, optimized on the sample rate of the input.  Future versions may vary the block size depending on the characteristics of the signal.<br />
+		<br />
+		Blocked data is passed to the predictor stage one subblock (channel) at a time.  Each subblock is independently coded into a subframe, and the subframes are concatenated into a frame.  Because each channel is coded separately, it means that one channel of a stereo frame may be encoded as a constant subframe, and the other an LPC subframe.<br />
+		<br />
+		<a name="interchannel"><font size="+1"><b><u>Interchannel Decorrelation</u></b></font></a><br />
+		<br />
+		In stereo streams, many times there is an exploitable amount of correlation between the left and right channels.  FLAC allows the frames of stereo streams to have different channel assignments, and an encoder may choose to use the best representation on a frame-by-frame basis.
+		<ul>
+			<li>
+				<b>Independent</b>.  The left and right channels are coded independently.
+			</li>
+			<li>
+				<b>Mid-side</b>.  The left and right channels are transformed into mid and side channels.  The mid channel is the midpoint (average) of the left and right signals, and the side is the difference signal (left minus right).
+			</li>
+			<li>
+				<b>Left-side</b>.  The left channel and side channel are coded.
+			</li>
+			<li>
+				<b>Right-side</b>.  The right channel and side channel are coded
+			</li>
+		</ul>
+		Surprisingly, the left-side and right-side forms can be the most efficient in many frames, even though the raw number of bits per sample needed for the original signal is slightly more than that needed for independent or mid-side coding.<br />
+		<br />
+		<a name="prediction"><font size="+1"><b><u>Prediction</u></b></font></a><br />
+		<br />
+		FLAC uses four methods for modeling the input signal:
+		<ul>
+			<li>
+				<b>Verbatim</b>.  This is essentially a zero-order predictor of the signal.  The predicted signal is zero, meaning the residual is the signal itself, and the compression is zero.  This is the baseline against which the other predictors are measured.  If you feed random data to the encoder, the verbatim predictor will probably be used for every subblock.  Since the raw signal is not actually passed through the residual coding stage (it is added to the stream 'verbatim'), the encoding results will not be the same as a zero-order linear predictor.
+			</li>
+			<li>
+				<b>Constant</b>.  This predictor is used whenever the subblock is pure DC ("digital silence"), i.e. a constant value throughout.  The signal is run-length encoded and added to the stream.
+			</li>
+			<li>
+				<b>Fixed linear predictor</b>.  FLAC uses a class of computationally-efficient fixed linear predictors (for a good description, see <a href="http://www.hpl.hp.com/techreports/1999/HPL-1999-144.pdf">audiopak</a> and <a href="http://svr-www.eng.cam.ac.uk/reports/abstracts/robinson_tr156.html">shorten</a>).  FLAC adds a fourth-order predictor to the zero-to-third-order predictors used by Shorten.  Since the predictors are fixed, the predictor order is the only parameter that needs to be stored in the compressed stream.  The error signal is then passed to the residual coder.
+			</li>
+			<li>
+				<b>FIR Linear prediction</b>.  For more accurate modeling (at a cost of slower encoding), FLAC supports up to 32nd order FIR linear prediction (again, for information on linear prediction, see <a href="http://www.hpl.hp.com/techreports/1999/HPL-1999-144.pdf">audiopak</a> and <a href="http://svr-www.eng.cam.ac.uk/reports/abstracts/robinson_tr156.html">shorten</a>).  The reference encoder uses the Levinson-Durbin method for calculating the LPC coefficients from the autocorrelation coefficients, and the coefficients are quantized before computing the residual.  Whereas encoders such as Shorten used a fixed quantization for the entire input, FLAC allows the quantized coefficient precision to vary from subframe to subframe.  The FLAC reference encoder estimates the optimal precision to use based on the block size and dynamic range of the original signal.
+			</li>
+		</ul>
+		<a name="residualcoding"><font size="+1"><b><u>Residual Coding</u></b></font></a><br />
+		<br />
+		FLAC currently defines two similar methods for the coding of the error signal from the prediction stage.  The error signal is coded using Rice codes in one of two ways: 1) the encoder estimates a single Rice parameter based on the variance of the residual and Rice codes the entire residual using this parameter; 2) the residual is partitioned into several equal-length regions of contiguous samples, and each region is coded with its own Rice parameter based on the region's mean.  (Note that the first method is a special case of the second method with one partition, except the Rice parameter is based on the residual variance instead of the mean.)<br />
+		<br />
+		The FLAC format has reserved space for other coding methods.  Some possibilities for volunteers would be to explore better context-modeling of the Rice parameter, or Huffman coding.  See <a href="http://www.hpl.hp.com/techreports/98/HPL-98-193.html">LOCO-I</a> and <a href="http://www.cs.tut.fi/~albert/Dev/pucrunch/packing.html">pucrunch</a> for descriptions of several universal codes.<br />
+		<br />
+		<a name="format_overview"><font size="+1"><b><u>Format</u></b></font></a><br />
+		<br />
+		This section specifies the FLAC bitstream format.  FLAC has no format version information, but it does contain reserved space in several places.  Future versions of the format may use this reserved space safely without breaking the format of older streams.  Older decoders may choose to abort decoding or skip data encoded with newer methods.  Apart from reserved patterns, in places the format specifies invalid patterns, meaning that the patterns may never appear in any valid bitstream, in any prior, present, or future versions of the format.  These invalid patterns are usually used to make the synchronization mechanism more robust.<br />
+		<br />
+		All numbers used in a FLAC bitstream are integers; there are no floating-point representations.  All numbers are big-endian coded.  All numbers are unsigned unless otherwise specified.<br />
+		<br />
+		Before the formal description of the stream, an overview might be helpful.
+		<ul>
+			<li>
+				A FLAC bitstream consists of the "fLaC" marker at the beginning of the stream, followed by a mandatory metadata block (called the STREAMINFO block), any number of other metadata blocks, then the audio frames.
+			</li>
+			<li>
+				FLAC supports up to 128 kinds of metadata blocks; currently the following are defined:
+				<ul>
+					<li><a name="def_STREAMINFO"><b>STREAMINFO</b></a>: This block has information about the whole stream, like sample rate, number of channels, total number of samples, etc.  It must be present as the first metadata block in the stream.  Other metadata blocks may follow, and ones that the decoder doesn't understand, it will skip.</li>
+					<li><a name="def_APPLICATION"><b>APPLICATION</b></a>: This block is for use by third-party applications.  The only mandatory field is a 32-bit identifier.  This ID is granted upon request to an application by the FLAC maintainers.  The remainder is of the block is defined by the registered application.  Visit the <a href="id.html">registration page</a> if you would like to register an ID for your application with FLAC.</li>
+					<li><a name="def_PADDING"><b>PADDING</b></a>: This block allows for an arbitrary amount of padding.  The contents of a PADDING block have no meaning.  This block is useful when it is known that metadata will be edited after encoding; the user can instruct the encoder to reserve a PADDING block of sufficient size so that when metadata is added, it will simply overwrite the padding (which is relatively quick) instead of having to insert it into the right place in the existing file (which would normally require rewriting the entire file).</li>
+					<li><a name="def_SEEKTABLE"><b>SEEKTABLE</b></a>: This is an optional block for storing seek points.  It is possible to seek to any given sample in a FLAC stream without a seek table, but the delay can be unpredictable since the bitrate may vary widely within a stream.  By adding seek points to a stream, this delay can be significantly reduced.  Each seek point takes 18 bytes, so 1% resolution within a stream adds less than 2k.  There can be only one SEEKTABLE in a stream, but the table can have any number of seek points.  There is also a special 'placeholder' seekpoint which will be ignored by decoders but which can be used to reserve space for future seek point insertion.</li>
+					<li><a name="def_VORBIS_COMMENT"><b>VORBIS_COMMENT</b></a>: This block is for storing a list of human-readable name/value pairs.  Values are encoded using UTF-8.  It is an implementation of the <a href="http://xiph.org/vorbis/doc/v-comment.html">Vorbis comment specification</a> (without the framing bit).  This is the only officially supported tagging mechanism in FLAC.  There may be only one VORBIS_COMMENT block in a stream.  In some external documentation, Vorbis comments are called FLAC tags to lessen confusion.</li>
+					<li><a name="def_CUESHEET"><b>CUESHEET</b></a>: This block is for storing various information that can be used in a cue sheet.  It supports track and index points, compatible with Red Book CD digital audio discs, as well as other CD-DA metadata such as media catalog number and track ISRCs.  The CUESHEET block is especially useful for backing up CD-DA discs, but it can be used as a general purpose cueing mechanism for playback.</li>
+					<li><a name="def_PICTURE"><b>PICTURE</b></a>: This block is for storing pictures associated with the file, most commonly cover art from CDs.  There may be more than one PICTURE block in a file.  The picture format is similar to the <a href="http://www.id3.org/id3v2.4.0-frames">APIC frame in ID3v2</a>.  The PICTURE block has a type, MIME type, and UTF-8 description like ID3v2, and supports external linking via URL (though this is discouraged).  The differences are that there is no uniqueness constraint on the description field, and the MIME type is mandatory.  The FLAC PICTURE block also includes the resolution, color depth, and palette size so that the client can search for a suitable picture without having to scan them all.</li>
+				</ul>
+			</li>
+			<li>
+				The audio data is composed of one or more audio frames.  Each frame consists of a frame header, which contains a sync code, information about the frame like the block size, sample rate, number of channels, et cetera, and an 8-bit CRC.  The frame header also contains either the sample number of the first sample in the frame (for variable-blocksize streams), or the frame number (for fixed-blocksize streams).  This allows for fast, sample-accurate seeking to be performed.  Following the frame header are encoded subframes, one for each channel, and finally, the frame is zero-padded to a byte boundary.  Each subframe has its own header that specifies how the subframe is encoded.
+			</li>
+			<li>
+				Since a decoder may start decoding in the middle of a stream, there must be a method to determine the start of a frame.  A 14-bit sync code begins each frame.  The sync code will not appear anywhere else in the frame header.  However, since it may appear in the subframes, the decoder has two other ways of ensuring a correct sync.  The first is to check that the rest of the frame header contains no invalid data.  Even this is not foolproof since valid header patterns can still occur within the subframes.  The decoder's final check is to generate an 8-bit CRC of the frame header and compare this to the CRC stored at the end of the frame header.
+			</li>
+			<li>
+				Again, since a decoder may start decoding at an arbitrary frame in the stream, each frame header must contain some basic information about the stream because the decoder may not have access to the STREAMINFO metadata block at the start of the stream.  This information includes sample rate, bits per sample, number of channels, etc.  Since the frame header is pure overhead, it has a direct effect on the compression ratio.  To keep the frame header as small as possible, FLAC uses lookup tables for the most commonly used values for frame parameters.  For instance, the sample rate part of the frame header is specified using 4 bits.  Eight of the bit patterns correspond to the commonly used sample rates of 8/16/22.05/24/32/44.1/48/96 kHz.  However, odd sample rates can be specified by using one of the 'hint' bit patterns, directing the decoder to find the exact sample rate at the end of the frame header.  The same method is used for specifying the block size and bits per sample.  In this way, the frame header size stays small for all of the most common forms of audio data.
+			</li>
+			<li>
+				Individual subframes (one for each channel) are coded separately within a frame, and appear serially in the stream.  In other words, the encoded audio data is NOT channel-interleaved.  This reduces decoder complexity at the cost of requiring larger decode buffers.  Each subframe has its own header specifying the attributes of the subframe, like prediction method and order, residual coding parameters, etc.  The header is followed by the encoded audio data for that channel.
+			</li>
+			<li>
+				<a name="subset">FLAC</a> specifies a subset of itself as the Subset format.  The purpose of this is to ensure that any streams encoded according to the Subset are truly "streamable", meaning that a decoder that cannot seek within the stream can still pick up in the middle of the stream and start decoding.  It also makes hardware decoder implementations more practical by limiting the encoding parameters such that decoder buffer sizes and other resource requirements can be easily determined.  <span class="commandname">flac</span> generates Subset streams by default unless the "--lax" command-line option is used.  The Subset makes the following limitations on what may be used in the stream:
+				<ul>
+				<li>
+					The blocksize bits in the <a href="#frame_header">frame header</a> must be 0001-1110.  The blocksize must be &lt;=16384; if the sample rate is &lt;= 48000Hz, the blocksize must be &lt;=4608.
+				</li>
+				<li>
+					The sample rate bits in the <a href="#frame_header">frame header</a> must be 0001-1110.
+				</li>
+				<li>
+					The bits-per-sample bits in the <a href="#frame_header">frame header</a> must be 001-111.
+				</li>
+				<li>
+					If the sample rate is &lt;= 48000Hz, the filter order in <a href="#subframe_lpc">LPC subframes</a> must be less than or equal to 12, i.e. the subframe type bits in the <a href="#subframe_header">subframe header</a> may not be 101100-111111.
+				</li>
+				<li>
+					The Rice partition order in a <a href="#partitioned_rice">Rice-coded residual section</a> must be less than or equal to 8.
+				</li>
+				</ul>
+			</li>
+		</ul>
+
+		The following tables constitute a formal description of the FLAC format.  Numbers in angle brackets indicate how many bits are used for a given field.<br />
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="stream"><font size="+1"><b>STREAM</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				"fLaC", the FLAC stream marker in ASCII, meaning byte 0 of the stream is 0x66, followed by 0x4C 0x61 0x43
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#metadata_block_streaminfo"><i>METADATA_BLOCK</i></a>
+			</td>
+			<td>
+				This is the mandatory STREAMINFO metadata block that has the basic properties of the stream
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#metadata_block"><i>METADATA_BLOCK</i></a>*
+			</td>
+			<td>
+				Zero or more metadata blocks
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#frame"><i>FRAME</i></a>+
+			</td>
+			<td>
+				One or more audio frames
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block"><font size="+1"><b>METADATA_BLOCK</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#metadata_block_header"><i>METADATA_BLOCK_HEADER</i></a>
+			</td>
+			<td>
+				A block header that specifies the type and size of the metadata block data.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#metadata_block_data"><i>METADATA_BLOCK_DATA</i></a>
+			</td>
+			<td>
+				&nbsp;
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_header"><font size="+1"><b>METADATA_BLOCK_HEADER</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1&gt;
+			</td>
+			<td>
+				Last-metadata-block flag: '1' if this block is the last metadata block before the audio blocks, '0' otherwise.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;7&gt;
+			</td>
+			<td>
+				BLOCK_TYPE<br />
+				<ul>
+				<li>
+					<tt>0</tt> : STREAMINFO
+				</li>
+				<li>
+					<tt>1</tt> : PADDING
+				</li>
+				<li>
+					<tt>2</tt> : APPLICATION
+				</li>
+				<li>
+					<tt>3</tt> : SEEKTABLE
+				</li>
+				<li>
+					<tt>4</tt> : VORBIS_COMMENT
+				</li>
+				<li>
+					<tt>5</tt> : CUESHEET
+				</li>
+				<li>
+					<tt>6</tt> : PICTURE
+				</li>
+				<li>
+					<tt>7-126</tt> : reserved
+				</li>
+				<li>
+					<tt>127</tt> : invalid, to avoid confusion with a frame sync code
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;24&gt;
+			</td>
+			<td>
+				Length (in bytes) of metadata to follow (does not include the size of the METADATA_BLOCK_HEADER)
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_data"><font size="+1"><b>METADATA_BLOCK_DATA</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#metadata_block_streaminfo"><i>METADATA_BLOCK_STREAMINFO</i></a><br />
+				|| <a href="#metadata_block_padding"><i>METADATA_BLOCK_PADDING</i></a><br />
+				|| <a href="#metadata_block_application"><i>METADATA_BLOCK_APPLICATION</i></a><br />
+				|| <a href="#metadata_block_seektable"><i>METADATA_BLOCK_SEEKTABLE</i></a><br />
+				|| <a href="#metadata_block_vorbis_comment"><i>METADATA_BLOCK_VORBIS_COMMENT</i></a><br />
+				|| <a href="#metadata_block_cuesheet"><i>METADATA_BLOCK_CUESHEET</i></a><br />
+				|| <a href="#metadata_block_picture"><i>METADATA_BLOCK_PICTURE</i></a>
+			</td>
+			<td>
+				The block data must match the block type in the block header.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_streaminfo"><font size="+1"><b>METADATA_BLOCK_STREAMINFO</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;16&gt;
+			</td>
+			<td>
+				The minimum block size (in samples) used in the stream.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;16&gt;
+			</td>
+			<td>
+				The maximum block size (in samples) used in the stream.  (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;24&gt;
+			</td>
+			<td>
+				The minimum frame size (in bytes) used in the stream.  May be 0 to imply the value is not known.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;24&gt;
+			</td>
+			<td>
+				The maximum frame size (in bytes) used in the stream.  May be 0 to imply the value is not known.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;20&gt;
+			</td>
+			<td>
+				Sample rate in Hz.  Though 20 bits are available, the maximum sample rate is limited by the structure of frame headers to 655350Hz.  Also, a value of 0 is invalid.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;3&gt;
+			</td>
+			<td>
+				(number of channels)-1.  FLAC supports from 1 to 8 channels
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;5&gt;
+			</td>
+			<td>
+				(bits per sample)-1.  FLAC supports from 4 to 32 bits per sample.  Currently the reference encoder and decoders only support up to 24 bits per sample.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;36&gt;
+			</td>
+			<td>
+				Total samples in stream.  'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels.  A value of zero here means the number of total samples is unknown.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;128&gt;
+			</td>
+			<td>
+				MD5 signature of the unencoded audio data.  This allows the decoder to determine if an error exists in the audio data even when the error does not result in an invalid bitstream.
+			</td>
+		</tr>
+		<tr>
+			<td>
+			</td>
+			<td bgcolor="#F4F4CC">
+				<font size="+1">NOTES</font><br />
+				<ul>
+				<li>
+					FLAC specifies a minimum block size of 16 and a maximum block size of 65535, meaning the bit patterns corresponding to the numbers 0-15 in the minimum blocksize and maximum blocksize fields are invalid.
+				</li>
+				</ul>
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_padding"><font size="+1"><b>METADATA_BLOCK_PADDING</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n&gt;
+			</td>
+			<td>
+				n '0' bits (n must be a multiple of 8)
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_application"><font size="+1"><b>METADATA_BLOCK_APPLICATION</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				Registered application ID.  (Visit the <a href="id.html">registration page</a> to register an ID with FLAC.)
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n&gt;
+			</td>
+			<td>
+				Application data (n must be a multiple of 8)
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_seektable"><font size="+1"><b>METADATA_BLOCK_SEEKTABLE</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#seekpoint"><i>SEEKPOINT</i></a>+
+			</td>
+			<td>
+				One or more seek points.
+			</td>
+		</tr>
+		<tr>
+			<td>
+			</td>
+			<td bgcolor="#F4F4CC">
+				<font size="+1">NOTE</font><br />
+				<ul>
+				<li>
+					The number of seek points is implied by the metadata header 'length' field, i.e. equal to length / 18.
+				</li>
+				</ul>
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="seekpoint"><font size="+1"><b>SEEKPOINT</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;64&gt;
+			</td>
+			<td>
+				Sample number of first sample in the target frame, or 0xFFFFFFFFFFFFFFFF for a placeholder point.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;64&gt;
+			</td>
+			<td>
+				Offset (in bytes) from the first byte of the first frame header to the first byte of the target frame's header.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;16&gt;
+			</td>
+			<td>
+				Number of samples in the target frame.
+			</td>
+		</tr>
+		<tr>
+			<td>
+			</td>
+			<td bgcolor="#F4F4CC">
+				<font size="+1">NOTES</font><br />
+				<ul>
+				<li>
+					For placeholder points, the second and third field values are undefined.
+				</li>
+				<li>
+					Seek points within a table must be sorted in ascending order by sample number.
+				</li>
+				<li>
+					Seek points within a table must be unique by sample number, with the exception of placeholder points.
+				</li>
+				<li>
+					The previous two notes imply that there may be any number of placeholder points, but they must all occur at the end of the table.
+				</li>
+				</ul>
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_vorbis_comment"><font size="+1"><b>METADATA_BLOCK_VORBIS_COMMENT</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n&gt;
+			</td>
+			<td>
+				Also known as FLAC tags, the contents of a vorbis comment packet as specified <a href="http://www.xiph.org/vorbis/doc/v-comment.html">here</a> (without the framing bit).  Note that the vorbis comment spec allows for on the order of 2 ^ 64 bytes of data where as the FLAC metadata block is limited to 2 ^ 24 bytes.  Given the stated purpose of vorbis comments, i.e. human-readable textual information, this limit is unlikely to be restrictive.  Also note that the 32-bit field lengths are little-endian coded according to the vorbis spec, as opposed to the usual big-endian coding of fixed-length integers in the rest of FLAC.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_cuesheet"><font size="+1"><b>METADATA_BLOCK_CUESHEET</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;128*8&gt;
+			</td>
+			<td>
+				Media catalog number, in ASCII printable characters 0x20-0x7e.  In general, the media catalog number may be 0 to 128 bytes long; any unused characters should be right-padded with NUL characters.  For CD-DA, this is a thirteen digit number, followed by 115 NUL bytes.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;64&gt;
+			</td>
+			<td>
+				The number of lead-in samples.  This field has meaning only for CD-DA cuesheets; for other uses it should be 0.  For CD-DA, the lead-in is the TRACK 00 area where the table of contents is stored; more precisely, it is the number of samples from the first sample of the media to the first sample of the first index point of the first track.  According to the Red Book, the lead-in must be silence and CD grabbing software does not usually store it; additionally, the lead-in must be at least two seconds but may be longer.  For these reasons the lead-in length is stored here so that the absolute position of the first track can be computed.  Note that the lead-in stored here is the number of samples up to the first index point of the first track, not necessarily to INDEX 01 of the first track; even the first track may have INDEX 00 data.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1&gt;
+			</td>
+			<td>
+				<tt>1</tt> if the CUESHEET corresponds to a Compact Disc, else <tt>0</tt>.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;7+258*8&gt;
+			</td>
+			<td>
+				Reserved.  All bits must be set to zero.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;8&gt;
+			</td>
+			<td>
+				The number of tracks.  Must be at least 1 (because of the requisite lead-out track).  For CD-DA, this number must be no more than 100 (99 regular tracks and one lead-out track).
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#cuesheet_track"><i>CUESHEET_TRACK</i></a>+
+			</td>
+			<td>
+				One or more tracks.  A CUESHEET block is required to have a lead-out track; it is always the last track in the CUESHEET.  For CD-DA, the lead-out track number must be 170 as specified by the Red Book, otherwise is must be 255.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="cuesheet_track"><font size="+1"><b>CUESHEET_TRACK</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;64&gt;
+			</td>
+			<td>
+				Track offset in samples, relative to the beginning of the FLAC audio stream.  It is the offset to the first index point of the track.  (Note how this differs from CD-DA, where the track's offset in the TOC is that of the track's INDEX 01 even if there is an INDEX 00.)  For CD-DA, the offset must be evenly divisible by 588 samples (588 samples = 44100 samples/sec * 1/75th of a sec).
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;8&gt;
+			</td>
+			<td>
+				Track number.  A track number of 0 is not allowed to avoid conflicting with the CD-DA spec, which reserves this for the lead-in.  For CD-DA the number must be 1-99, or 170 for the lead-out; for non-CD-DA, the track number must for 255 for the lead-out.  It is not required but encouraged to start with track 1 and increase sequentially.  Track numbers must be unique within a CUESHEET.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;12*8&gt;
+			</td>
+			<td>
+				Track ISRC.  This is a 12-digit alphanumeric code; see <a href="http://isrc.ifpi.org/">here</a> and <a href="http://www.disctronics.co.uk/technology/cdaudio/cdaud_isrc.htm">here</a>.  A value of 12 ASCII NUL characters may be used to denote absence of an ISRC.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1&gt;
+			</td>
+			<td>
+				The track type: 0 for audio, 1 for non-audio.  This corresponds to the CD-DA Q-channel control bit 3.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1&gt;
+			</td>
+			<td>
+				The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis.  This corresponds to the CD-DA Q-channel control bit 5; see <a href="http://www.chipchapin.com/CDMedia/cdda9.php3">here</a>.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;6+13*8&gt;
+			</td>
+			<td>
+				Reserved.  All bits must be set to zero.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;8&gt;
+			</td>
+			<td>
+				The number of track index points.  There must be at least one index in every track in a CUESHEET except for the lead-out track, which must have zero.  For CD-DA, this number may be no more than 100.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#cuesheet_track_index"><i>CUESHEET_TRACK_INDEX</i></a>+
+			</td>
+			<td>
+				For all tracks except the lead-out track, one or more track index points.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="cuesheet_track_index"><font size="+1"><b>CUESHEET_TRACK_INDEX</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;64&gt;
+			</td>
+			<td>
+				Offset in samples, relative to the track offset, of the index point.  For CD-DA, the offset must be evenly divisible by 588 samples (588 samples = 44100 samples/sec * 1/75th of a sec).  Note that the offset is from the beginning of the track, not the beginning of the audio data.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;8&gt;
+			</td>
+			<td>
+				The index point number.  For CD-DA, an index number of 0 corresponds to the track pre-gap.  The first index in a track must have a number of 0 or 1, and subsequently, index numbers must increase by 1.  Index numbers must be unique within a track.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;3*8&gt;
+			</td>
+			<td>
+				Reserved.  All bits must be set to zero.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="metadata_block_picture"><font size="+1"><b>METADATA_BLOCK_PICTURE</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				The picture type according to the ID3v2 APIC frame:<br />
+				<ul>
+					<li>0 - Other</li>
+					<li>1 - 32x32 pixels 'file icon' (PNG only)</li>
+					<li>2 - Other file icon</li>
+					<li>3 - Cover (front)</li>
+					<li>4 - Cover (back)</li>
+					<li>5 - Leaflet page</li>
+					<li>6 - Media (e.g. label side of CD)</li>
+					<li>7 - Lead artist/lead performer/soloist</li>
+					<li>8 - Artist/performer</li>
+					<li>9 - Conductor</li>
+					<li>10 - Band/Orchestra</li>
+					<li>11 - Composer</li>
+					<li>12 - Lyricist/text writer</li>
+					<li>13 - Recording Location</li>
+					<li>14 - During recording</li>
+					<li>15 - During performance</li>
+					<li>16 - Movie/video screen capture</li>
+					<li>17 - A bright coloured fish</li>
+					<li>18 - Illustration</li>
+					<li>19 - Band/artist logotype</li>
+					<li>20 - Publisher/Studio logotype</li>
+				</ul>
+				Others are reserved and should not be used.  There may only be one each of picture type 1 and 2 in a file.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				The length of the MIME type string in bytes.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n*8&gt;
+			</td>
+			<td>
+				The MIME type string, in printable ASCII characters 0x20-0x7e.  The MIME type may also be <tt>--&gt;</tt> to signify that the data part is a URL of the picture instead of the picture data itself.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				The length of the description string in bytes.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n*8&gt;
+			</td>
+			<td>
+				The description of the picture, in UTF-8.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				The width of the picture in pixels.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				The height of the picture in pixels.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				The color depth of the picture in bits-per-pixel.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				For indexed-color pictures (e.g. GIF), the number of colors used, or <tt>0</tt> for non-indexed pictures.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;32&gt;
+			</td>
+			<td>
+				The length of the picture data in bytes.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n*8&gt;
+			</td>
+			<td>
+				The binary picture data.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="frame"><font size="+1"><b>FRAME</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#frame_header"><i>FRAME_HEADER</i></a>
+			</td>
+			<td>
+				&nbsp;
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#subframe"><i>SUBFRAME</i></a>+
+			</td>
+			<td>
+				One SUBFRAME per channel.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;?&gt;
+			</td>
+			<td>
+				Zero-padding to byte alignment.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#frame_footer"><i>FRAME_FOOTER</i></a>
+			</td>
+			<td>
+				&nbsp;
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="frame_header"><font size="+1"><b>FRAME_HEADER</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;14&gt;
+			</td>
+			<td>
+				Sync code '<tt>11111111111110</tt>'
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1&gt;
+			</td>
+			<td>
+				Reserved: <a href="#frame_header_notes">[1]</a><br />
+				<ul>
+				<li>
+					<tt>0</tt> : mandatory value
+				</li>
+				<li>
+					<tt>1</tt> : reserved for future use
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1&gt;
+			</td>
+			<td>
+				Blocking strategy: <a href="#frame_header_notes">[2]</a> <a href="#frame_header_notes">[3]</a><br />
+				<ul>
+				<li>
+					<tt>0</tt> : fixed-blocksize stream; frame header encodes the frame number
+				</li>
+				<li>
+					<tt>1</tt> : variable-blocksize stream; frame header encodes the sample number
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;4&gt;
+			</td>
+			<td>
+				Block size in inter-channel samples:<br />
+				<ul>
+				<li>
+					<tt>0000</tt> : reserved
+				</li>
+				<li>
+					<tt>0001</tt> : 192 samples
+				</li>
+				<li>
+					<tt>0010-0101</tt> : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
+				</li>
+				<li>
+					<tt>0110</tt> : get 8 bit (blocksize-1) from end of header
+				</li>
+				<li>
+					<tt>0111</tt> : get 16 bit (blocksize-1) from end of header
+				</li>
+				<li>
+					<tt>1000-1111</tt> : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;4&gt;
+			</td>
+			<td>
+				Sample rate:<br />
+				<ul>
+				<li>
+					<tt>0000</tt> : get from STREAMINFO metadata block
+				</li>
+				<li>
+					<tt>0001</tt> : 88.2kHz
+				</li>
+				<li>
+					<tt>0010</tt> : 176.4kHz
+				</li>
+				<li>
+					<tt>0011</tt> : 192kHz
+				</li>
+				<li>
+					<tt>0100</tt> : 8kHz
+				</li>
+				<li>
+					<tt>0101</tt> : 16kHz
+				</li>
+				<li>
+					<tt>0110</tt> : 22.05kHz
+				</li>
+				<li>
+					<tt>0111</tt> : 24kHz
+				</li>
+				<li>
+					<tt>1000</tt> : 32kHz
+				</li>
+				<li>
+					<tt>1001</tt> : 44.1kHz
+				</li>
+				<li>
+					<tt>1010</tt> : 48kHz
+				</li>
+				<li>
+					<tt>1011</tt> : 96kHz
+				</li>
+				<li>
+					<tt>1100</tt> : get 8 bit sample rate (in kHz) from end of header
+				</li>
+				<li>
+					<tt>1101</tt> : get 16 bit sample rate (in Hz) from end of header
+				</li>
+				<li>
+					<tt>1110</tt> : get 16 bit sample rate (in tens of Hz) from end of header
+				</li>
+				<li>
+					<tt>1111</tt> : invalid, to prevent sync-fooling string of 1s
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;4&gt;
+			</td>
+			<td>
+				Channel assignment
+				<ul>
+				<li>
+					<tt>0000-0111</tt> : (number of independent channels)-1.  Where defined, the channel order follows SMPTE/ITU-R recommendations.  The assignments are as follows:
+					<ul>
+						<li>1 channel: mono</li>
+						<li>2 channels: left, right</li>
+						<li>3 channels: left, right, center</li>
+						<li>4 channels: front left, front right, back left, back right</li>
+						<li>5 channels: front left, front right, front center, back/surround left, back/surround right</li>
+						<li>6 channels: front left, front right, front center, LFE, back/surround left, back/surround right</li>
+						<li>7 channels: front left, front right, front center, LFE, back center, side left, side right</li>
+						<li>8 channels: front left, front right, front center, LFE, back left, back right, side left, side right</li>
+					</ul>
+				</li>
+				<li>
+					<tt>1000</tt> : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
+				</li>
+				<li>
+					<tt>1001</tt> : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
+				</li>
+				<li>
+					<tt>1010</tt> : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
+				</li>
+				<li>
+					<tt>1011-1111</tt> : reserved
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;3&gt;
+			</td>
+			<td>
+				Sample size in bits: <a href="#frame_header_notes">[5]</a><br />
+				<ul>
+				<li>
+					<tt>000</tt> : get from STREAMINFO metadata block
+				</li>
+				<li>
+					<tt>001</tt> : 8 bits per sample
+				</li>
+				<li>
+					<tt>010</tt> : 12 bits per sample
+				</li>
+				<li>
+					<tt>011</tt> : reserved
+				</li>
+				<li>
+					<tt>100</tt> : 16 bits per sample
+				</li>
+				<li>
+					<tt>101</tt> : 20 bits per sample
+				</li>
+				<li>
+					<tt>110</tt> : 24 bits per sample
+				</li>
+				<li>
+					<tt>111</tt> : reserved
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1&gt;
+			</td>
+			<td>
+				Reserved:<br />
+				<ul>
+				<li>
+					<tt>0</tt> : mandatory value
+				</li>
+				<li>
+					<tt>1</tt> : reserved for future use
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;?&gt;
+			</td>
+			<td>
+				if(variable blocksize)<br />
+				&nbsp;&nbsp;&nbsp;&lt;8-56&gt;:"UTF-8" coded sample number (decoded number is 36 bits) <a href="#frame_header_notes">[4]</a><br />
+				else<br />
+				&nbsp;&nbsp;&nbsp;&lt;8-48&gt;:"UTF-8" coded frame number (decoded number is 31 bits) <a href="#frame_header_notes">[4]</a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;?&gt;
+			</td>
+			<td>
+				if(blocksize bits == 011x)<br />
+				&nbsp;&nbsp;&nbsp;8/16 bit (blocksize-1)
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;?&gt;
+			</td>
+			<td>
+				if(sample rate bits == 11xx)<br />
+				&nbsp;&nbsp;&nbsp;8/16 bit sample rate
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;8&gt;
+			</td>
+			<td>
+				CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) of everything before the crc, including the sync code
+			</td>
+		</tr>
+		<tr>
+			<td>
+			</td>
+			<td bgcolor="#F4F4CC">
+				<a name="frame_header_notes"><font size="+1">NOTES</font></a><br />
+				<ol>
+				<li>
+					This bit must remain reserved for <tt>0</tt> in order for a FLAC frame's initial 15 bits to be distinguishable from the start of an MPEG audio frame (<a href="http://lists.xiph.org/pipermail/flac-dev/2008-December/002607.html">see also</a>).
+				</li>
+				<li>
+					The "blocking strategy" bit must be the same throughout the entire stream.
+				</li>
+				<li>
+					The "blocking strategy" bit determines how to calculate the sample number of the first sample in the frame.  If the bit is <tt>0</tt> (fixed-blocksize), the frame header encodes the frame number as above, and the frame's starting sample number will be the frame number times the blocksize.  If it is <tt>1</tt> (variable-blocksize), the frame header encodes the frame's starting sample number itself.  (In the case of a fixed-blocksize stream, only the last block may be shorter than the stream blocksize; its starting sample number will be calculated as the frame number times the previous frame's blocksize, or zero if it is the first frame).
+				</li>
+				<li>
+					The "UTF-8" coding used for the sample/frame number is the same variable length code used to store compressed UCS-2, extended to handle larger input.
+				</li>
+				<li>
+					For subframes that encode a difference channel,
+					the sample size is one bit larger than the sample size of the frame,
+					in order to be able to encode the difference between extreme values.
+				</li>
+				</ol>
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="frame_footer"><font size="+1"><b>FRAME_FOOTER</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;16&gt;
+			</td>
+			<td>
+				CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with 0) of everything before the crc, back to and including the frame header sync code
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="subframe"><font size="+1"><b>SUBFRAME</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#subframe_header"><i>SUBFRAME_HEADER</i></a>
+			</td>
+			<td>
+				&nbsp;
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#subframe_constant"><i>SUBFRAME_CONSTANT</i></a><br />|| <a href="#subframe_fixed"><i>SUBFRAME_FIXED</i></a><br />|| <a href="#subframe_lpc"><i>SUBFRAME_LPC</i></a><br />|| <a href="#subframe_verbatim"><i>SUBFRAME_VERBATIM</i></a>
+			</td>
+			<td valign="top">
+				The SUBFRAME_HEADER specifies which one.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="subframe_header"><font size="+1"><b>SUBFRAME_HEADER</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1&gt;
+			</td>
+			<td>
+				Zero bit padding, to prevent sync-fooling string of 1s
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;6&gt;
+			</td>
+			<td>
+				Subframe type:
+				<ul>
+				<li>
+					<tt>000000</tt> : <a href="#subframe_constant">SUBFRAME_CONSTANT</a>
+				</li>
+				<li>
+					<tt>000001</tt> : <a href="#subframe_verbatim">SUBFRAME_VERBATIM</a>
+				</li>
+				<li>
+					<tt>00001x</tt> : reserved
+				</li>
+				<li>
+					<tt>0001xx</tt> : reserved
+				</li>
+				<li>
+					<tt>001xxx</tt> : if(xxx &lt;= 4) <a href="#subframe_fixed">SUBFRAME_FIXED</a>, xxx=order ; else reserved
+				</li>
+				<li>
+					<tt>01xxxx</tt> : reserved
+				</li>
+				<li>
+					<tt>1xxxxx</tt> : <a href="#subframe_lpc">SUBFRAME_LPC</a>, xxxxx=order-1
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;1+k&gt;
+			</td>
+			<td>
+				'Wasted bits-per-sample' flag:
+				<ul>
+				<li>
+					<tt>0</tt> : no wasted bits-per-sample in source subblock, k=0
+				</li>
+				<li>
+					<tt>1</tt> : k wasted bits-per-sample in source subblock, k-1 follows, unary coded; e.g. k=3 =&gt; 001 follows, k=7 =&gt; 0000001 follows.
+				</li>
+				</ul>
+				The size of the samples stored in the subframe is the subframe sample size reduced by k bits.
+				Decoded samples must be shifted left by k bits.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="subframe_constant"><font size="+1"><b>SUBFRAME_CONSTANT</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n&gt;
+			</td>
+			<td>
+				Unencoded constant value of the subblock, n = frame's bits-per-sample.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="subframe_fixed"><font size="+1"><b>SUBFRAME_FIXED</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n&gt;
+			</td>
+			<td>
+				Unencoded warm-up samples (n = frame's bits-per-sample * predictor order).
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#residual"><i>RESIDUAL</i></a>
+			</td>
+			<td>
+				Encoded residual
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="subframe_lpc"><font size="+1"><b>SUBFRAME_LPC</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n&gt;
+			</td>
+			<td>
+				Unencoded warm-up samples (n = frame's bits-per-sample * lpc order).
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;4&gt;
+			</td>
+			<td>
+				(Quantized linear predictor coefficients' precision in bits)-1 (1111 = invalid).
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;5&gt;
+			</td>
+			<td>
+				Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed two's-complement;
+				but, due to implementation details, must be non-negative).
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n&gt;
+			</td>
+			<td>
+				Unencoded predictor coefficients (n = qlp coeff precision * lpc order) (NOTE: the coefficients are signed two's-complement).
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#residual"><i>RESIDUAL</i></a>
+			</td>
+			<td>
+				Encoded residual
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="subframe_verbatim"><font size="+1"><b>SUBFRAME_VERBATIM</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;n*i&gt;
+			</td>
+			<td>
+				Unencoded subblock; n = frame's bits-per-sample, i = frame's blocksize.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="residual"><font size="+1"><b>RESIDUAL</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;2&gt;
+			</td>
+			<td>
+				Residual coding method:<br />
+				<ul>
+				<li>
+					<tt>00</tt> : partitioned Rice coding with 4-bit Rice parameter; RESIDUAL_CODING_METHOD_PARTITIONED_RICE follows
+				</li>
+				<li>
+					<tt>01</tt> : partitioned Rice coding with 5-bit Rice parameter; RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 follows
+				</li>
+				<li>
+					<tt>10-11</tt> : reserved
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#partitioned_rice"><i>RESIDUAL_CODING_METHOD_PARTITIONED_RICE</i></a>&nbsp;||<br />
+				<a href="#partitioned_rice2"><i>RESIDUAL_CODING_METHOD_PARTITIONED_RICE2</i></a>
+			</td>
+			<td>
+				&nbsp;
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="partitioned_rice"><font size="+1"><b>RESIDUAL_CODING_METHOD_PARTITIONED_RICE</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;4&gt;
+			</td>
+			<td>
+				Partition order.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#rice_partition"><i>RICE_PARTITION</i></a>+
+			</td>
+			<td>
+				There will be 2^order partitions.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="rice_partition"><font size="+1"><b>RICE_PARTITION</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;4(+5)&gt;
+			</td>
+			<td>
+				Encoding parameter:<br />
+				<ul>
+				<li>
+					<tt>0000-1110</tt> : Rice parameter.
+				</li>
+				<li>
+					<tt>1111</tt> : Escape code, meaning the partition is in unencoded binary form using n bits per sample; n follows as a 5-bit number.
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;?&gt;
+			</td>
+			<td>
+				Encoded residual.  The number of samples (n) in the partition is determined as follows:<br />
+				<ul>
+				<li>
+					partition size = (frame's blocksize / (2^partition order))
+				</li>
+				<li>
+					for first partition of the subframe, n = partition size - predictor
+				</li>
+				<li>
+					for remaining partitions, n = partition size
+				</li>
+				</ul>
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="partitioned_rice2"><font size="+1"><b>RESIDUAL_CODING_METHOD_PARTITIONED_RICE2</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;4&gt;
+			</td>
+			<td>
+				Partition order.
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				<a href="#rice2_partition"><i>RICE2_PARTITION</i></a>+
+			</td>
+			<td>
+				There will be 2^order partitions.
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+<br />
+
+<div class="box">
+	<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+	<table width="100%" border="1" bgcolor="#EEEED4">
+		<tr>
+			<td colspan="2" bgcolor="#D3D4C5">
+				<a name="rice2_partition"><font size="+1"><b>RICE2_PARTITION</b></font></a>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;5(+5)&gt;
+			</td>
+			<td>
+				Encoding parameter:<br />
+				<ul>
+				<li>
+					<tt>00000-11110</tt> : Rice parameter.
+				</li>
+				<li>
+					<tt>11111</tt> : Escape code, meaning the partition is in unencoded binary form using n bits per sample; n follows as a 5-bit number.
+				</li>
+				</ul>
+			</td>
+		</tr>
+		<tr>
+			<td align="right" valign="top" bgcolor="#F4F4CC">
+				&lt;?&gt;
+			</td>
+			<td>
+				Encoded residual.  The number of samples (n) in the partition is determined as follows:<br />
+				<ul>
+				<li>
+					partition size = (frame's blocksize / (2^partition order))
+				</li>
+				<li>
+					for first partition of the subframe, n = partition size - predictor
+				</li>
+				<li>
+					for remaining partitions, n = partition size
+				</li>
+				</ul>
+			</td>
+		</tr>
+	</table>
+	</td></tr></table>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/id.html b/doc/html/id.html
new file mode 100644
index 0000000..ac05427
--- /dev/null
+++ b/doc/html/id.html
@@ -0,0 +1,289 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--  Copyright (c) 2000-2009  Josh Coalson -->
+<!--  Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - id</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		register
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		FLAC allows third-party applications to register an ID for use with FLAC <a href="format.html#def_APPLICATION">APPLICATION metadata blocks</a>. <a href="http://lists.xiph.org/mailman/listinfo/flac-dev">Contact the FLAC-dev mailinglist</a> to register an ID or to change an existing ID. Your request should at least contain the application ID, application name and a contact e-mail address. An application URL and specification URL should be mentioned too, if applicable.<br />
+		<br />
+		The ID request should be 8 hexadecimal digits and not conflict with any existing IDs (see the table below for all currently registered IDs).  This 32-bit number will be stored big-endian in the block.<br />
+		<br />
+		Information about your application (but not your e-mail address) will show up on this page in the ID directory.  You can also provide a URL to your application and a URL reference to the specification of your application's APPLICATION block.<br />
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+<br />
+
+<div class="box">
+	<div class="box_title">
+		<a name="directory">id directory</a>
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		Here is a list of all registered IDs and their applications:<br />
+		<br />
+		<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
+		<table width="100%" border="1" bgcolor="#EEEED4">
+			<tr>
+				<td bgcolor="#D3D4C5">
+					<font size="+1"><b>ID</b></font>
+				</td>
+				<td bgcolor="#D3D4C5">
+					<font size="+1"><b>Application</b></font>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>41544348 - "ATCH"</tt>
+				</td>
+				<td>
+					<a href="http://firestuff.org/flacfile/">FlacFile</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>42534F4C - "BSOL"</tt>
+				</td>
+				<td>
+					beSolo
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>42554753 - "BUGS"</tt>
+				</td>
+				<td>
+					<a href="http://www.neowizbugs.com/">Bugs Player</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>43756573 - "Cues"</tt>
+				</td>
+				<td>
+					<a href="http://www.goldwave.com">GoldWave</a> cue points (<a href="http://www.goldwave.com/developer.php">specification</a>)
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>46696361 - "Fica"</tt>
+				</td>
+				<td>
+					<a href="http://www.enfis.it/details.php?id=24">CUE Splitter</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>46746F6C - "Ftol"</tt>
+				</td>
+				<td>
+					<a href="http://flac-tools.sourceforge.net/">flac-tools</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>4D4F5442 - "MOTB"</tt>
+				</td>
+				<td>
+					<a href="http://www.motb.org/">MOTB MetaCzar</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>4D505345 - "MPSE"</tt>
+				</td>
+				<td>
+					<a href="http://www.3delite.hu/MP3SE/index.html">MP3 Stream Editor</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>4D754D4C - "MuML"</tt>
+				</td>
+				<td>
+					MusicML: Music Metadata Language
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>52494646 - "RIFF"</tt>
+				</td>
+				<td>
+					Sound Devices RIFF chunk storage
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>5346464C - "SFFL"</tt>
+				</td>
+				<td>
+					Sound Font FLAC
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>534F4E59 - "SONY"</tt>
+				</td>
+				<td>
+					<a href="http://www.sonycreativesoftware.com/">Sony Creative Software</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>5351455A - "SQEZ"</tt>
+				</td>
+				<td>
+					flacsqueeze
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>54745776 - "TtWv"</tt>
+				</td>
+				<td>
+					<a href="http://twistedwave.com/">TwistedWave</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>55495453 - "UITS"</tt>
+				</td>
+				<td>
+					UITS Embedding tools
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>61696666 - "aiff"</tt>
+				</td>
+				<td>
+					FLAC AIFF chunk storage
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>696D6167 - "imag"</tt>
+				</td>
+				<td>
+					<a href="http://www.singingtree.com/software/">flac-image</a> application for storing arbitrary files in APPLICATION metadata blocks
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>7065656D - "peem"</tt>
+				</td>
+				<td>
+					<a href="http://peem.iconoclast.net/">Parseable Embedded Extensible Metadata</a> (<a href="http://peem.iconoclast.net/1.0/">specification</a>)
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>71667374 - "qfst"</tt>
+				</td>
+				<td>
+					<a href="http://qflacstudio.sourceforge.net/">QFLAC Studio</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>72696666 - "riff"</tt>
+				</td>
+				<td>
+					FLAC RIFF chunk storage
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>74756E65 - "tune"</tt>
+				</td>
+				<td>
+					<a href="http://www.tagtuner.com/">TagTuner</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>78626174 - "xbat"</tt>
+				</td>
+				<td>
+					<a href="http://xbat.org/">XBAT</a>
+				</td>
+			</tr>
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					<tt>786D6364 - "xmcd"</tt>
+				</td>
+				<td>
+					<a href="http://www.amb.org/xmcd/">xmcd</a>
+				</td>
+			</tr>
+		<!--
+			<tr>
+				<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
+					deadbeef
+				</td>
+				<td>
+					<a href="x">Application1</a> (<a href="y">specification</a>)
+				</td>
+			</tr>
+		-->
+		</table>
+		</td></tr></table>
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/images/Makefile.am b/doc/html/images/Makefile.am
new file mode 100644
index 0000000..467651c
--- /dev/null
+++ b/doc/html/images/Makefile.am
@@ -0,0 +1,25 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+logosdir = $(htmldir)/images
+
+logos_DATA = \
+	logo.svg \
+	logo130.gif
+
+EXTRA_DIST = $(logos_DATA)
diff --git a/doc/html/images/logo.svg b/doc/html/images/logo.svg
new file mode 100644
index 0000000..4ee2d41
--- /dev/null
+++ b/doc/html/images/logo.svg
@@ -0,0 +1,431 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   width="262"
+   height="130"
+   sodipodi:docname="logo.svg"
+   inkscape:export-filename="/home/martijn/bin/flac/doc/html/images/logo130.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata8">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6">
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath4747">
+      <rect
+         y="108.66365"
+         x="58.024467"
+         height="31.744326"
+         width="208.41971"
+         id="rect4749"
+         style="fill:#ffffff;fill-opacity:0.91542287;stroke:#41b348;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+    </clipPath>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1680"
+     inkscape:window-height="971"
+     id="namedview4"
+     showgrid="false"
+     inkscape:zoom="3.8432063"
+     inkscape:cx="50.316519"
+     inkscape:cy="46.312655"
+     inkscape:window-x="-4"
+     inkscape:window-y="-6"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2" />
+  <rect
+     style="fill:#000000;fill-opacity:1;stroke:none"
+     id="rect2987"
+     width="262"
+     height="130"
+     x="0"
+     y="1.7763568e-15" />
+  <rect
+     style="fill:#34a02c;fill-opacity:1;stroke:none"
+     id="rect2989"
+     width="8.3984327"
+     height="11.97043"
+     x="2.8360443"
+     y="114.36095"
+     inkscape:tile-cx="7.0352583"
+     inkscape:tile-cy="120.34616"
+     inkscape:tile-w="8.3984327"
+     inkscape:tile-h="11.97043"
+     inkscape:tile-x0="2.8360419"
+     inkscape:tile-y0="114.36095" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="114.36095"
+     x="2.8360443"
+     height="11.97043"
+     width="8.3984327"
+     id="use4591"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="98.440277"
+     x="2.8360443"
+     height="11.97043"
+     width="8.3984327"
+     id="use4593"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="82.5196"
+     x="2.8360443"
+     height="11.97043"
+     width="8.3984327"
+     id="use4595"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="66.59893"
+     x="2.8360443"
+     height="11.97043"
+     width="8.3984327"
+     id="use4597"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="50.678257"
+     x="2.8360443"
+     height="11.97043"
+     width="8.3984327"
+     id="use4599"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="34.757584"
+     x="2.8360443"
+     height="11.97043"
+     width="8.3984327"
+     id="use4601"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="18.836912"
+     x="2.8360443"
+     height="11.97043"
+     width="8.3984327"
+     id="use4603"
+     style="fill:#ff0000;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="2.9162366"
+     x="2.8360443"
+     height="11.97043"
+     width="8.3984327"
+     id="use4605"
+     style="fill:#ff0000;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="114.36095"
+     x="15.853616"
+     height="11.97043"
+     width="8.3984327"
+     id="use4607"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="98.440277"
+     x="15.853616"
+     height="11.97043"
+     width="8.3984327"
+     id="use4609"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="82.5196"
+     x="15.853616"
+     height="11.97043"
+     width="8.3984327"
+     id="use4611"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="66.59893"
+     x="15.853616"
+     height="11.97043"
+     width="8.3984327"
+     id="use4613"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="50.678257"
+     x="15.853616"
+     height="11.97043"
+     width="8.3984327"
+     id="use4615"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="34.757584"
+     x="15.853616"
+     height="11.97043"
+     width="8.3984327"
+     id="use4617"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="114.36095"
+     x="28.871185"
+     height="11.97043"
+     width="8.3984327"
+     id="use4623"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="98.440277"
+     x="28.871185"
+     height="11.97043"
+     width="8.3984327"
+     id="use4625"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="82.5196"
+     x="28.871185"
+     height="11.97043"
+     width="8.3984327"
+     id="use4627"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="66.59893"
+     x="28.871185"
+     height="11.97043"
+     width="8.3984327"
+     id="use4629"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="50.678257"
+     x="28.871185"
+     height="11.97043"
+     width="8.3984327"
+     id="use4631"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="34.757584"
+     x="28.871185"
+     height="11.97043"
+     width="8.3984327"
+     id="use4633"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="18.836912"
+     x="28.871185"
+     height="11.97043"
+     width="8.3984327"
+     id="use4635"
+     style="fill:#ff0000;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="114.36095"
+     x="41.888756"
+     height="11.97043"
+     width="8.3984327"
+     id="use4639"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="98.440277"
+     x="41.888756"
+     height="11.97043"
+     width="8.3984327"
+     id="use4641"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="82.5196"
+     x="41.888756"
+     height="11.97043"
+     width="8.3984327"
+     id="use4643"
+     style="fill:#34a02c;fill-opacity:1;stroke:none" />
+  <rect
+     inkscape:tile-y0="114.36095"
+     inkscape:tile-x0="2.8360419"
+     y="66.59893"
+     x="41.888756"
+     height="11.97043"
+     width="8.3984327"
+     id="use4645"
+     style="fill:#ffff00;fill-opacity:1;stroke:none" />
+  <g
+     id="g4740"
+     style="fill:#ffffff;fill-opacity:1">
+    <path
+       id="path4719"
+       d="m 167.09375,30.28125 c -4.98582,-0.05597 -10.83371,0.544011 -17.65625,2.03125 L 146.25,50.90625 c 6.2402,-3.841378 28.72275,-6.439176 29.15625,4.03125 l 0.25,6.375 c -20.10772,-13.818292 -38.48096,-0.631226 -39.0625,19.125 -0.58154,19.75623 24.38101,31.46172 38.875,16 l 0.0625,5.875 17.375,-1.53125 1.15625,-49.375 c 0.19095,-8.148311 -5.36352,-20.882474 -26.96875,-21.125 z m -1.90625,38.875 c 5.33673,0 9.65625,4.075677 9.65625,9.125 0,5.049323 -4.31952,9.15625 -9.65625,9.15625 -5.33673,0 -9.65625,-4.106927 -9.65625,-9.15625 0,-5.049323 4.31952,-9.125 9.65625,-9.125 z"
+       style="fill:#ffffff;fill-opacity:1;stroke:none"
+       inkscape:connector-curvature="0" />
+    <path
+       sodipodi:nodetypes="ccccccccccccc"
+       inkscape:connector-curvature="0"
+       id="path4705"
+       d="m 66.419944,102.30969 20.238764,-2.29986 0,-49.492976 10.855337,0 0,-17.662922 -11.223315,0 c 1.030499,-9.919211 4.729089,-9.43064 17.29494,-9.199438 L 98.617978,4.335674 C 88.053405,4.3210512 66.008231,6.32016 66.419944,32.669944 l -6.807584,0 -3.863764,17.662921 10.671348,0.183989 z"
+       style="fill:#ffffff;fill-opacity:1;stroke:none" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:none"
+       d="m 108.94803,102.30969 20.23877,-2.29986 0,-93.3270875 -20.23877,2.2078652 z"
+       id="path4707"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       sodipodi:nodetypes="sssccsccccs"
+       inkscape:connector-curvature="0"
+       id="path4723"
+       d="m 231.29725,30.118335 c -9.62029,0.652151 -17.24238,4.090284 -24.04461,11.842706 -13.60446,15.504845 -12.39784,39.604586 3.18708,53.122515 15.58492,13.517924 40.64278,8.399604 47.71564,-0.389642 L 247.34775,78.958636 c -6.47017,7.37397 -15.93762,7.267658 -23.36382,0.82638 -7.42621,-6.441278 -8.1621,-17.252972 -1.69193,-24.626942 l 0.11279,-0.112795 c 6.48447,-7.259969 17.70592,-7.662694 25.09092,-1.257152 l 10.86397,-15.411334 c -7.76321,-6.645971 -17.51834,-8.905444 -27.06243,-8.258458 z"
+       style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" />
+  </g>
+  <g
+     style="font-size:17.05998611px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Swis721 BT;-inkscape-font-specification:Swis721 BT"
+     id="text4751">
+    <path
+       d="m 70.858501,114.93679 0,1.16008 -1.484218,0 0,7.77935 -1.415979,0 0,-7.77935 -1.194199,0 0,-1.16008 1.194199,0 0,-1.51834 c -2e-6,-0.6369 0.181971,-1.13163 0.545919,-1.48422 0.375318,-0.36393 0.892803,-0.54591 1.552459,-0.54592 0.261583,10e-6 0.528855,0.0284 0.801819,0.0853 l 0,1.17714 c -0.216097,-0.0114 -0.38101,-0.017 -0.494739,-0.0171 -0.659656,1e-5 -0.989482,0.3014 -0.989479,0.90418 l 0,1.39892 1.484218,0"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4756" />
+    <path
+       d="m 76.510422,116.18217 c -0.955364,0.0228 -1.671883,0.24453 -2.149559,0.66534 -0.477682,0.42082 -0.716521,1.21695 -0.716519,2.38839 l 0,4.64032 -1.433039,0 0,-8.93943 1.313619,0 0,1.6207 c 0.409437,-0.67102 0.801816,-1.1487 1.177139,-1.43304 0.386689,-0.2957 0.807502,-0.44355 1.262439,-0.44356 0.125102,10e-6 0.307075,0.0171 0.54592,0.0512 l 0,1.4501"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4758" />
+    <path
+       d="m 85.433328,119.88418 -6.585155,0 c 0.02275,0.93262 0.261584,1.67757 0.71652,2.23486 0.466303,0.5573 1.103208,0.83594 1.910718,0.83594 1.160073,0 1.939145,-0.5971 2.337218,-1.7913 l 1.433039,0 c -0.181981,0.97811 -0.608481,1.74012 -1.279499,2.28604 -0.671033,0.54592 -1.518344,0.81888 -2.541938,0.81888 -1.251069,0 -2.240547,-0.42081 -2.968438,-1.26244 -0.727893,-0.853 -1.091839,-2.01307 -1.091839,-3.48024 0,-1.46715 0.369632,-2.6386 1.108899,-3.51435 0.750637,-0.88711 1.745802,-1.33067 2.985498,-1.33068 2.649977,10e-6 3.974968,1.73444 3.974977,5.20329 m -6.551035,-1.16008 5.032696,0 c -7e-6,-0.77338 -0.23316,-1.42165 -0.699459,-1.94483 -0.466313,-0.52317 -1.057725,-0.78476 -1.774239,-0.78476 -0.716523,0 -1.307936,0.25022 -1.774239,0.75064 -0.466308,0.48906 -0.727894,1.14871 -0.784759,1.97895"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4760" />
+    <path
+       d="m 94.529766,119.88418 -6.585154,0 c 0.02274,0.93262 0.261584,1.67757 0.716519,2.23486 0.466303,0.5573 1.103209,0.83594 1.910718,0.83594 1.160074,0 1.939146,-0.5971 2.337218,-1.7913 l 1.433039,0 c -0.181981,0.97811 -0.60848,1.74012 -1.279499,2.28604 -0.671032,0.54592 -1.518344,0.81888 -2.541938,0.81888 -1.251069,0 -2.240547,-0.42081 -2.968437,-1.26244 -0.727894,-0.853 -1.09184,-2.01307 -1.091839,-3.48024 -10e-7,-1.46715 0.369632,-2.6386 1.108899,-3.51435 0.750637,-0.88711 1.745802,-1.33067 2.985497,-1.33068 2.649978,10e-6 3.974969,1.73444 3.974977,5.20329 m -6.551035,-1.16008 5.032696,0 c -7e-6,-0.77338 -0.23316,-1.42165 -0.699459,-1.94483 -0.466312,-0.52317 -1.057724,-0.78476 -1.774239,-0.78476 -0.716523,0 -1.307935,0.25022 -1.774238,0.75064 -0.466309,0.48906 -0.727895,1.14871 -0.78476,1.97895"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4762" />
+    <path
+       d="m 102.74554,111.43949 0,12.43673 -1.43304,0 0,-12.43673 1.43304,0"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4764" />
+    <path
+       d="m 108.49209,114.68089 c 1.28518,10e-6 2.28034,0.42651 2.9855,1.2795 0.71651,0.84163 1.07477,2.03583 1.07478,3.58259 -1e-5,1.46717 -0.36396,2.62156 -1.09184,3.46318 -0.71653,0.84163 -1.70032,1.26244 -2.95138,1.26244 -1.27382,0 -2.26898,-0.42081 -2.9855,-1.26244 -0.70515,-0.853 -1.05772,-2.03013 -1.05772,-3.53142 0,-1.50127 0.35826,-2.67272 1.07478,-3.51435 0.71652,-0.85299 1.70031,-1.27949 2.95138,-1.2795 m 0.0171,1.31362 c -0.79614,0 -1.42167,0.31277 -1.8766,0.9383 -0.45494,0.61416 -0.6824,1.46147 -0.6824,2.54193 0,1.08047 0.22746,1.93347 0.6824,2.559 0.45493,0.61416 1.08046,0.92124 1.8766,0.92124 0.78475,0 1.4046,-0.30708 1.85954,-0.92124 0.4663,-0.62553 0.69945,-1.46147 0.69946,-2.50782 -1e-5,-1.1032 -0.22748,-1.96757 -0.6824,-2.59311 -0.44357,-0.62553 -1.0691,-0.9383 -1.8766,-0.9383"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4766" />
+    <path
+       d="m 115.13189,121.21486 c 0.0682,0.53455 0.25021,0.96105 0.54592,1.2795 0.30707,0.30708 0.85299,0.46062 1.63775,0.46062 0.62553,0 1.12596,-0.1251 1.50128,-0.37532 0.38669,-0.26158 0.58004,-0.60278 0.58004,-1.0236 0,-0.32982 -0.10805,-0.59141 -0.32414,-0.78476 -0.2161,-0.19334 -0.56867,-0.34688 -1.05772,-0.46062 l -1.33068,-0.32414 c -1.05772,-0.25021 -1.79698,-0.56297 -2.21779,-0.9383 -0.40944,-0.38668 -0.61416,-0.9326 -0.61416,-1.63775 0,-0.83025 0.31276,-1.4899 0.9383,-1.97896 0.62553,-0.50042 1.45578,-0.75063 2.49075,-0.75064 1.03497,10e-6 1.8311,0.23885 2.3884,0.71652 0.55729,0.47769 0.84162,1.1544 0.853,2.03014 l -1.50128,0 c -0.0341,-0.95536 -0.63122,-1.43304 -1.7913,-1.43304 -0.58004,0 -1.04066,0.12511 -1.38185,0.37532 -0.34121,0.23884 -0.51181,0.56298 -0.5118,0.97242 -10e-6,0.31846 0.13079,0.58004 0.39238,0.78476 0.26158,0.19335 0.68239,0.35826 1.26243,0.49473 l 1.3648,0.32414 c 0.88712,0.2161 1.52971,0.52318 1.92778,0.92124 0.39806,0.3867 0.59709,0.90987 0.5971,1.56952 -1e-5,0.86438 -0.33552,1.55246 -1.00654,2.06426 -0.65966,0.5118 -1.55246,0.7677 -2.67842,0.7677 -2.30878,0 -3.49729,-1.01791 -3.56553,-3.05374 l 1.50128,0"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4768" />
+    <path
+       d="m 123.5286,121.21486 c 0.0682,0.53455 0.25021,0.96105 0.54592,1.2795 0.30708,0.30708 0.85299,0.46062 1.63776,0.46062 0.62553,0 1.12595,-0.1251 1.50128,-0.37532 0.38668,-0.26158 0.58003,-0.60278 0.58004,-1.0236 -1e-5,-0.32982 -0.10806,-0.59141 -0.32414,-0.78476 -0.2161,-0.19334 -0.56868,-0.34688 -1.05772,-0.46062 l -1.33068,-0.32414 c -1.05772,-0.25021 -1.79699,-0.56297 -2.2178,-0.9383 -0.40944,-0.38668 -0.61416,-0.9326 -0.61416,-1.63775 0,-0.83025 0.31277,-1.4899 0.9383,-1.97896 0.62553,-0.50042 1.45578,-0.75063 2.49076,-0.75064 1.03496,10e-6 1.8311,0.23885 2.3884,0.71652 0.55728,0.47769 0.84161,1.1544 0.85299,2.03014 l -1.50127,0 c -0.0341,-0.95536 -0.63123,-1.43304 -1.7913,-1.43304 -0.58005,0 -1.04066,0.12511 -1.38186,0.37532 -0.3412,0.23884 -0.5118,0.56298 -0.5118,0.97242 0,0.31846 0.13079,0.58004 0.39238,0.78476 0.26158,0.19335 0.68239,0.35826 1.26244,0.49473 l 1.3648,0.32414 c 0.88711,0.2161 1.5297,0.52318 1.92777,0.92124 0.39806,0.3867 0.5971,0.90987 0.5971,1.56952 0,0.86438 -0.33552,1.55246 -1.00653,2.06426 -0.65966,0.5118 -1.55247,0.7677 -2.67842,0.7677 -2.30879,0 -3.4973,-1.01791 -3.56554,-3.05374 l 1.50128,0"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4770" />
+    <path
+       d="m 132.30063,111.43949 0,12.43673 -1.43304,0 0,-12.43673 1.43304,0"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4772" />
+    <path
+       d="m 142.0904,119.88418 -6.58516,0 c 0.0228,0.93262 0.26159,1.67757 0.71652,2.23486 0.4663,0.5573 1.10321,0.83594 1.91072,0.83594 1.16007,0 1.93915,-0.5971 2.33722,-1.7913 l 1.43304,0 c -0.18198,0.97811 -0.60848,1.74012 -1.2795,2.28604 -0.67103,0.54592 -1.51835,0.81888 -2.54194,0.81888 -1.25107,0 -2.24055,-0.42081 -2.96844,-1.26244 -0.72789,-0.853 -1.09184,-2.01307 -1.09184,-3.48024 0,-1.46715 0.36964,-2.6386 1.1089,-3.51435 0.75064,-0.88711 1.7458,-1.33067 2.9855,-1.33068 2.64998,10e-6 3.97497,1.73444 3.97498,5.20329 m -6.55104,-1.16008 5.0327,0 c -1e-5,-0.77338 -0.23316,-1.42165 -0.69946,-1.94483 -0.46631,-0.52317 -1.05773,-0.78476 -1.77424,-0.78476 -0.71652,0 -1.30794,0.25022 -1.77424,0.75064 -0.46631,0.48906 -0.72789,1.14871 -0.78476,1.97895"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4774" />
+    <path
+       d="m 144.68698,121.21486 c 0.0682,0.53455 0.25021,0.96105 0.54592,1.2795 0.30707,0.30708 0.85299,0.46062 1.63776,0.46062 0.62552,0 1.12595,-0.1251 1.50127,-0.37532 0.38669,-0.26158 0.58004,-0.60278 0.58004,-1.0236 0,-0.32982 -0.10805,-0.59141 -0.32414,-0.78476 -0.21609,-0.19334 -0.56867,-0.34688 -1.05771,-0.46062 l -1.33068,-0.32414 c -1.05773,-0.25021 -1.79699,-0.56297 -2.2178,-0.9383 -0.40944,-0.38668 -0.61416,-0.9326 -0.61416,-1.63775 0,-0.83025 0.31276,-1.4899 0.9383,-1.97896 0.62553,-0.50042 1.45578,-0.75063 2.49076,-0.75064 1.03496,10e-6 1.8311,0.23885 2.38839,0.71652 0.55729,0.47769 0.84162,1.1544 0.853,2.03014 l -1.50128,0 c -0.0341,-0.95536 -0.63122,-1.43304 -1.79129,-1.43304 -0.58005,0 -1.04067,0.12511 -1.38186,0.37532 -0.3412,0.23884 -0.5118,0.56298 -0.5118,0.97242 0,0.31846 0.13079,0.58004 0.39238,0.78476 0.26158,0.19335 0.68239,0.35826 1.26244,0.49473 l 1.3648,0.32414 c 0.88711,0.2161 1.5297,0.52318 1.92777,0.92124 0.39806,0.3867 0.5971,0.90987 0.5971,1.56952 0,0.86438 -0.33552,1.55246 -1.00654,2.06426 -0.65966,0.5118 -1.55246,0.7677 -2.67841,0.7677 -2.30879,0 -3.4973,-1.01791 -3.56554,-3.05374 l 1.50128,0"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4776" />
+    <path
+       d="m 153.08369,121.21486 c 0.0682,0.53455 0.25021,0.96105 0.54592,1.2795 0.30708,0.30708 0.853,0.46062 1.63776,0.46062 0.62553,0 1.12595,-0.1251 1.50128,-0.37532 0.38668,-0.26158 0.58003,-0.60278 0.58004,-1.0236 -1e-5,-0.32982 -0.10806,-0.59141 -0.32414,-0.78476 -0.2161,-0.19334 -0.56867,-0.34688 -1.05772,-0.46062 l -1.33068,-0.32414 c -1.05772,-0.25021 -1.79699,-0.56297 -2.2178,-0.9383 -0.40944,-0.38668 -0.61416,-0.9326 -0.61416,-1.63775 0,-0.83025 0.31277,-1.4899 0.9383,-1.97896 0.62553,-0.50042 1.45578,-0.75063 2.49076,-0.75064 1.03497,10e-6 1.8311,0.23885 2.3884,0.71652 0.55728,0.47769 0.84162,1.1544 0.853,2.03014 l -1.50128,0 c -0.0341,-0.95536 -0.63123,-1.43304 -1.7913,-1.43304 -0.58004,0 -1.04066,0.12511 -1.38186,0.37532 -0.3412,0.23884 -0.5118,0.56298 -0.5118,0.97242 0,0.31846 0.13079,0.58004 0.39238,0.78476 0.26158,0.19335 0.6824,0.35826 1.26244,0.49473 l 1.3648,0.32414 c 0.88711,0.2161 1.5297,0.52318 1.92778,0.92124 0.39806,0.3867 0.59709,0.90987 0.5971,1.56952 -1e-5,0.86438 -0.33552,1.55246 -1.00654,2.06426 -0.65966,0.5118 -1.55247,0.7677 -2.67842,0.7677 -2.30879,0 -3.4973,-1.01791 -3.56554,-3.05374 l 1.50128,0"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4778" />
+    <path
+       d="m 165.54714,117.58109 c 0.0682,-1.93346 1.26244,-2.90019 3.5826,-2.9002 1.1032,10e-6 1.93914,0.21041 2.50781,0.63122 0.56866,0.40945 0.853,1.01223 0.853,1.80836 l 0,5.25447 c 0,0.46631 0.25589,0.69946 0.7677,0.69946 0.10235,0 0.20471,-0.0114 0.30708,-0.0341 l 0,1.07478 c -0.39807,0.10236 -0.72221,0.15354 -0.97242,0.15354 -0.45494,0 -0.80182,-0.10805 -1.04066,-0.32414 -0.22747,-0.20472 -0.36964,-0.53455 -0.4265,-0.98948 -0.95536,0.87575 -1.96759,1.31362 -3.03667,1.31362 -0.8985,0 -1.61502,-0.23884 -2.14956,-0.71652 -0.52318,-0.47768 -0.78476,-1.12027 -0.78476,-1.92778 0,-0.26158 0.0228,-0.50042 0.0682,-0.71652 0.0569,-0.21609 0.11373,-0.40375 0.1706,-0.56298 0.0682,-0.17059 0.18197,-0.32413 0.3412,-0.46062 0.15922,-0.14785 0.29002,-0.26726 0.39238,-0.35826 0.11373,-0.091 0.2957,-0.17628 0.54592,-0.2559 0.26158,-0.091 0.46062,-0.15353 0.5971,-0.18766 0.13647,-0.0455 0.37531,-0.0967 0.71652,-0.15354 0.34119,-0.0569 0.59141,-0.0967 0.75064,-0.11942 0.15922,-0.0227 0.44355,-0.0625 0.853,-0.11942 0.55728,-0.0682 0.94398,-0.17628 1.16007,-0.32413 0.21609,-0.14785 0.32414,-0.36963 0.32414,-0.66534 l 0,-0.37532 c 0,-0.43218 -0.17629,-0.76201 -0.52886,-0.98948 -0.3412,-0.22746 -0.83025,-0.3412 -1.46715,-0.3412 -0.65966,0 -1.16009,0.1308 -1.50128,0.39238 -0.34121,0.25022 -0.54024,0.64828 -0.5971,1.1942 l -1.43304,0 m 2.84902,5.44213 c 0.78475,0 1.42734,-0.20472 1.92777,-0.61416 0.50043,-0.42081 0.75064,-0.87006 0.75064,-1.34774 l 0,-1.60364 c -0.28433,0.13649 -0.71652,0.25022 -1.29655,0.3412 -0.56868,0.091 -1.06341,0.17061 -1.48422,0.23884 -0.42082,0.0683 -0.80183,0.23316 -1.14302,0.49474 -0.3412,0.25022 -0.5118,0.60279 -0.5118,1.05772 0,0.45494 0.15354,0.80751 0.46062,1.05772 0.30707,0.25022 0.73926,0.37532 1.29656,0.37532"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4780" />
+    <path
+       d="m 182.04361,123.87622 -1.2795,0 0,-1.24538 c -0.42082,0.59142 -0.85869,1.01223 -1.31362,1.26244 -0.45493,0.25021 -1.01223,0.37532 -1.67187,0.37532 -0.86438,0 -1.55815,-0.22178 -2.08132,-0.66534 -0.5118,-0.44356 -0.7677,-1.03497 -0.7677,-1.77424 l 0,-6.89223 1.41598,0 0,6.32925 c -1e-5,0.53455 0.16491,0.96105 0.49474,1.2795 0.32982,0.31846 0.77906,0.47768 1.34773,0.47768 0.73927,0 1.33068,-0.27296 1.77424,-0.81888 0.44356,-0.55729 0.66534,-1.29087 0.66534,-2.20074 l 0,-5.06681 1.41598,0 0,8.93943"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4782" />
+    <path
+       d="m 191.58201,111.43949 0,12.43673 -1.26244,0 0,-1.17714 c -0.3867,0.5573 -0.80751,0.95536 -1.26244,1.1942 -0.44356,0.25021 -0.97242,0.37532 -1.58658,0.37532 -1.20557,0 -2.15524,-0.43219 -2.84901,-1.29656 -0.69378,-0.87574 -1.04066,-2.06994 -1.04066,-3.5826 0,-1.42166 0.34688,-2.55899 1.04066,-3.41199 0.70514,-0.86437 1.63775,-1.29655 2.79783,-1.29656 1.22832,10e-6 2.14387,0.46063 2.74666,1.38186 l 0,-4.62326 1.41598,0 m -3.9238,4.57208 c -0.77339,0 -1.39892,0.31846 -1.8766,0.95536 -0.47768,0.63691 -0.71652,1.47285 -0.71652,2.50781 0,1.04635 0.23884,1.88798 0.71652,2.52488 0.47768,0.62554 1.1089,0.9383 1.89366,0.9383 0.75064,0 1.35342,-0.31276 1.80836,-0.9383 0.45493,-0.62553 0.68239,-1.45578 0.6824,-2.49076 -1e-5,-1.06908 -0.22747,-1.91639 -0.6824,-2.54193 -0.45494,-0.6369 -1.06341,-0.95536 -1.82542,-0.95536"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4784" />
+    <path
+       d="m 195.15768,114.93679 0,8.93943 -1.41598,0 0,-8.93943 1.41598,0 m 0,-3.4973 0,1.7913 -1.43304,0 0,-1.7913 1.43304,0"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4786" />
+    <path
+       d="m 200.93515,114.68089 c 1.28518,10e-6 2.28034,0.42651 2.9855,1.2795 0.71651,0.84163 1.07477,2.03583 1.07478,3.58259 -1e-5,1.46717 -0.36396,2.62156 -1.09184,3.46318 -0.71653,0.84163 -1.70032,1.26244 -2.95138,1.26244 -1.27382,0 -2.26898,-0.42081 -2.9855,-1.26244 -0.70514,-0.853 -1.05772,-2.03013 -1.05772,-3.53142 0,-1.50127 0.35826,-2.67272 1.07478,-3.51435 0.71652,-0.85299 1.70031,-1.27949 2.95138,-1.2795 m 0.0171,1.31362 c -0.79614,0 -1.42167,0.31277 -1.8766,0.9383 -0.45493,0.61416 -0.6824,1.46147 -0.6824,2.54193 0,1.08047 0.22747,1.93347 0.6824,2.559 0.45493,0.61416 1.08046,0.92124 1.8766,0.92124 0.78475,0 1.4046,-0.30708 1.85954,-0.92124 0.4663,-0.62553 0.69945,-1.46147 0.69946,-2.50782 -1e-5,-1.1032 -0.22748,-1.96757 -0.6824,-2.59311 -0.44357,-0.62553 -1.0691,-0.9383 -1.8766,-0.9383"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4788" />
+    <path
+       d="m 218.75569,117.93935 -1.43304,0 c -0.091,-0.62553 -0.31846,-1.10321 -0.6824,-1.43304 -0.36395,-0.3412 -0.84163,-0.5118 -1.43304,-0.5118 -0.77339,0 -1.38186,0.31846 -1.82542,0.95536 -0.43219,0.62554 -0.64828,1.49559 -0.64828,2.61017 0,1.05773 0.22178,1.88798 0.66534,2.49076 0.44356,0.60279 1.05772,0.90418 1.84248,0.90418 1.21694,0 1.94483,-0.71652 2.18368,-2.14956 l 1.43304,0 c -0.091,1.09184 -0.45494,1.94484 -1.09184,2.559 -0.63691,0.60279 -1.48991,0.90418 -2.559,0.90418 -1.21695,0 -2.18368,-0.42081 -2.9002,-1.26244 -0.70514,-0.853 -1.05772,-2.0017 -1.05771,-3.44612 -1e-5,-1.47852 0.35825,-2.66135 1.07477,-3.54847 0.72789,-0.88711 1.69463,-1.33067 2.9002,-1.33068 1.03497,10e-6 1.85953,0.27865 2.4737,0.83594 0.62552,0.5573 0.9781,1.3648 1.05772,2.42252"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4790" />
+    <path
+       d="m 223.90541,114.68089 c 1.28518,10e-6 2.28035,0.42651 2.9855,1.2795 0.71651,0.84163 1.07477,2.03583 1.07478,3.58259 -1e-5,1.46717 -0.36396,2.62156 -1.09184,3.46318 -0.71653,0.84163 -1.70032,1.26244 -2.95138,1.26244 -1.27381,0 -2.26898,-0.42081 -2.9855,-1.26244 -0.70514,-0.853 -1.05772,-2.03013 -1.05772,-3.53142 0,-1.50127 0.35826,-2.67272 1.07478,-3.51435 0.71652,-0.85299 1.70031,-1.27949 2.95138,-1.2795 m 0.0171,1.31362 c -0.79614,0 -1.42167,0.31277 -1.8766,0.9383 -0.45493,0.61416 -0.6824,1.46147 -0.6824,2.54193 0,1.08047 0.22747,1.93347 0.6824,2.559 0.45493,0.61416 1.08046,0.92124 1.8766,0.92124 0.78475,0 1.4046,-0.30708 1.85954,-0.92124 0.4663,-0.62553 0.69945,-1.46147 0.69946,-2.50782 -1e-5,-1.1032 -0.22747,-1.96757 -0.6824,-2.59311 -0.44357,-0.62553 -1.0691,-0.9383 -1.8766,-0.9383"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4792" />
+    <path
+       d="m 236.97682,111.43949 0,12.43673 -1.26244,0 0,-1.17714 c -0.3867,0.5573 -0.80751,0.95536 -1.26243,1.1942 -0.44357,0.25021 -0.97243,0.37532 -1.58658,0.37532 -1.20558,0 -2.15525,-0.43219 -2.84902,-1.29656 -0.69377,-0.87574 -1.04066,-2.06994 -1.04066,-3.5826 0,-1.42166 0.34689,-2.55899 1.04066,-3.41199 0.70514,-0.86437 1.63775,-1.29655 2.79784,-1.29656 1.22831,10e-6 2.14386,0.46063 2.74665,1.38186 l 0,-4.62326 1.41598,0 m -3.92379,4.57208 c -0.77339,0 -1.39893,0.31846 -1.8766,0.95536 -0.47768,0.63691 -0.71652,1.47285 -0.71652,2.50781 0,1.04635 0.23884,1.88798 0.71652,2.52488 0.47767,0.62554 1.10889,0.9383 1.89366,0.9383 0.75063,0 1.35342,-0.31276 1.80835,-0.9383 0.45493,-0.62553 0.6824,-1.45578 0.6824,-2.49076 0,-1.06908 -0.22747,-1.91639 -0.6824,-2.54193 -0.45493,-0.6369 -1.06341,-0.95536 -1.82541,-0.95536"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4794" />
+    <path
+       d="m 246.57467,119.88418 -6.58516,0 c 0.0228,0.93262 0.26158,1.67757 0.71652,2.23486 0.4663,0.5573 1.10321,0.83594 1.91072,0.83594 1.16007,0 1.93914,-0.5971 2.33722,-1.7913 l 1.43304,0 c -0.18199,0.97811 -0.60849,1.74012 -1.2795,2.28604 -0.67104,0.54592 -1.51835,0.81888 -2.54194,0.81888 -1.25107,0 -2.24055,-0.42081 -2.96844,-1.26244 -0.72789,-0.853 -1.09184,-2.01307 -1.09184,-3.48024 0,-1.46715 0.36963,-2.6386 1.1089,-3.51435 0.75064,-0.88711 1.7458,-1.33067 2.9855,-1.33068 2.64998,10e-6 3.97497,1.73444 3.97498,5.20329 m -6.55104,-1.16008 5.0327,0 c -1e-5,-0.77338 -0.23316,-1.42165 -0.69946,-1.94483 -0.46632,-0.52317 -1.05773,-0.78476 -1.77424,-0.78476 -0.71652,0 -1.30794,0.25022 -1.77424,0.75064 -0.46631,0.48906 -0.72789,1.14871 -0.78476,1.97895"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4796" />
+    <path
+       d="m 255.10812,117.93935 -1.43304,0 c -0.091,-0.62553 -0.31846,-1.10321 -0.6824,-1.43304 -0.36395,-0.3412 -0.84163,-0.5118 -1.43304,-0.5118 -0.77339,0 -1.38186,0.31846 -1.82541,0.95536 -0.43219,0.62554 -0.64829,1.49559 -0.64828,2.61017 -1e-5,1.05773 0.22177,1.88798 0.66534,2.49076 0.44355,0.60279 1.05771,0.90418 1.84247,0.90418 1.21694,0 1.94484,-0.71652 2.18368,-2.14956 l 1.43304,0 c -0.091,1.09184 -0.45494,1.94484 -1.09184,2.559 -0.63691,0.60279 -1.48991,0.90418 -2.559,0.90418 -1.21694,0 -2.18368,-0.42081 -2.90019,-1.26244 -0.70515,-0.853 -1.05772,-2.0017 -1.05772,-3.44612 0,-1.47852 0.35826,-2.66135 1.07478,-3.54847 0.72789,-0.88711 1.69462,-1.33067 2.90019,-1.33068 1.03497,10e-6 1.85954,0.27865 2.4737,0.83594 0.62553,0.5573 0.9781,1.3648 1.05772,2.42252"
+       style="word-spacing:0.97887385px;fill:#ffffff;font-family:FreeSans;-inkscape-font-specification:FreeSans"
+       id="path4798" />
+  </g>
+</svg>
diff --git a/doc/html/images/logo130.gif b/doc/html/images/logo130.gif
new file mode 100644
index 0000000..3200df3
--- /dev/null
+++ b/doc/html/images/logo130.gif
Binary files differ
diff --git a/doc/html/index.html b/doc/html/index.html
new file mode 100644
index 0000000..3dabbd1
--- /dev/null
+++ b/doc/html/index.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2000-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - Free Lossless Audio Codec</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;home&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<table border="0" cellpadding="0" cellspacing="0">
+	<tr>
+		<td width="60%" align="center" valign="top">
+
+			<div class="box">
+				<div class="box_title">
+					<a name="what_is_flac">what is FLAC?</a>
+				</div>
+				<div class="box_header"></div>
+				<div class="box_body">
+					<b>Please note: This is the source-code documentation, for more general information on FLAC, please visit <a href="http://xiph.org/flac">the on-line FLAC homepage</a></b><br />
+					<br />
+					FLAC stands for Free Lossless Audio Codec, an audio format similar to MP3, but lossless, meaning that audio is compressed in FLAC without any loss in quality.  This is similar to how Zip works, except with FLAC you will get much better compression because it is designed specifically for audio, and you can play back compressed FLAC files in your favorite player (or your car or home stereo, see <a href="http://xiph.org/flac/links.html#hardware">supported devices</a>) just like you would an MP3 file.<br />
+					<br />
+					FLAC stands out as the <a href="http://xiph.org/flac/comparison.html">fastest and most widely supported lossless audio codec</a>, and the only one that at once is non-proprietary, is unencumbered by patents, has an open-source reference implementation, has a well documented format and API, and has several other independent implementations.<br />
+					<br />
+					See <a href="features.html">About FLAC</a> for more, or <a href="http://xiph.org/flac/documentation_tasks.html">Using FLAC</a> for how to play FLAC files, rip CDs to FLAC, etc.
+				</div>
+				<div class="box_footer"></div>
+			</div>
+
+		</td>
+
+
+		<td width="40%" align="center" valign="top">
+
+			<div class="box" style="margin-left: 5px;">
+				<div class="box_title">
+					<a name="latest">the latest dev-news</a>
+				</div>
+				<div class="box_header"></div>
+				<div class="box_body">
+					<b>FLAC 1.3.2 released</b>&nbsp;&nbsp;:<a href="changelog.html#flac_1.3.2">Changelog here</a><br />
+					<i>last updated 2016-Dec-5</i>
+				</div>
+				<div class="box_footer"></div>
+			</div>
+
+		</td>
+	</tr>
+</table>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2000-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/license.html b/doc/html/license.html
new file mode 100644
index 0000000..2273388
--- /dev/null
+++ b/doc/html/license.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2004-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - license</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		license
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		FLAC is a free codec in the fullest sense.  This page explicitly states all that you may do with the format and software.<br />
+		<br />
+		The FLAC and Ogg FLAC formats themselves, and their specifications, are fully open to the public to be used for any purpose (the FLAC project reserves the right to set the FLAC specification and certify compliance).  They are free for commercial or noncommercial use.  That means that commercial developers may independently write FLAC or Ogg FLAC software which is compatible with the specifications for no charge and without restrictions of any kind.  There are no licensing fees or royalties of any kind for use of the formats or their specifications, or for distributing, selling, or streaming media in the FLAC or Ogg FLAC formats.<br />
+		<br />
+		The FLAC project also makes available software that implements the formats, which is distributed according to <a href="http://opensource.org/docs/definition.php">Open Source</a> licenses as follows:<br />
+		<br />
+		The reference implementation libraries are licensed under the New <!-- <a href="http://www.xiph.org/licenses/bsd/"> --><a href="https://git.xiph.org/?p=flac.git;a=blob_plain;f=COPYING.Xiph">BSD License</a>.  In simple terms, these libraries may be used by any application, Open or proprietary, linked or incorporated in whole, so long as acknowledgement is made to Xiph.org Foundation when using the source code in whole or in derived works.  The Xiph License is free enough that the libraries have been used in commercial products to implement FLAC, including in the firmware of hardware devices where other Open Source licenses can be problematic.  In the source code these libraries are called <span class="commandname">libFLAC</span> and <span class="commandname">libFLAC++</span>.<br />
+		<br />
+		The rest of the software that the FLAC project provides is licensed under the <a href="http://www.gnu.org/licenses/licenses.html#GPL">GNU General Public License</a> (GPL).  This software includes various utilities for converting files to and from FLAC format, plugins for audio players, et cetera.  In general, the GPL allows redistribution as long as derived works are also made available in source code form according to compatible terms.<br />
+		<br />
+		Neither the FLAC nor Ogg FLAC formats nor any of the implemented encoding/decoding methods are covered by any known patent.<br />
+		<br />
+		FLAC is one of a family of codecs of the Xiph.org Foundation, all created according to the same free ideals.  For some other codecs' descriptions of the Xiph License see the <a href="http://speex.org/fsos/">Speex</a> and <a href="http://www.vorbis.com/faq/#flic">Vorbis</a> license pages.<br />
+		<br />
+		If you would like to redistribute parts or all of FLAC under different terms, <a href="http://lists.xiph.org/mailman/listinfo/flac-dev">contact the FLAC-dev mailinglist</a>.
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2004-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/html/ogg_mapping.html b/doc/html/ogg_mapping.html
new file mode 100644
index 0000000..e28ca3d
--- /dev/null
+++ b/doc/html/ogg_mapping.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- Copyright (c) 2004-2009  Josh Coalson -->
+<!-- Copyright (c) 2011-2016  Xiph.Org Foundation -->
+<!-- Permission is granted to copy, distribute and/or modify this document -->
+<!-- under the terms of the GNU Free Documentation License, Version 1.1 -->
+<!-- or any later version published by the Free Software Foundation; -->
+<!-- with no invariant sections. -->
+<!-- A copy of the license can be found at http://www.gnu.org/copyleft/fdl.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<meta name="author" content="Josh Coalson" />
+	<meta name="description" content="A free, open source codec for lossless audio compression and decompression" />
+	<meta name="keywords" content="free,lossless,audio,codec,encoder,decoder,compression,compressor,archival,archive,archiving,backup,music" />
+	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+	<link rel="stylesheet" type="text/css" href="flac.css" />
+	<title>FLAC - ogg mapping</title>
+</head>
+
+<body>
+
+<div class="logo">
+	<a href="index.html"><img src="images/logo130.gif" alt="FLAC Logo" align="middle" border="0" hspace="0" /></a>
+</div>
+
+<div class="above_nav"></div>
+
+<div class="navbar">
+	&nbsp;<a href="index.html">home</a>&nbsp;&nbsp;|
+	&nbsp;<a href="faq.html">faq</a>&nbsp;&nbsp;|
+	&nbsp;<a href="documentation.html">documentation</a>&nbsp;&nbsp;|
+	&nbsp;<a href="developers.html">developers</a>&nbsp;&nbsp;|
+	&nbsp;<a href="changelog.html">changelog</a>&nbsp;&nbsp;|
+	&nbsp;<a href="http://xiph.org/flac">more</a>
+</div>
+
+<div class="below_nav"></div>
+
+<div class="box">
+	<div class="box_title">
+		ogg mapping
+	</div>
+	<div class="box_header"></div>
+	<div class="box_body">
+		This page specifies the way in which compressed FLAC data is encapsulated in an Ogg transport layer.  It assumes basic knowledge of the <a href="format.html">FLAC format</a> and <a href="http://xiph.org/vorbis/doc/oggstream.html">Ogg structure</a> and <a href="http://xiph.org/vorbis/doc/framing.html">framing</a>.<br />
+		<br />
+		The original FLAC format includes a very thin transport system.  This system of compressed FLAC audio data mixed with a thin transport has come to be known as 'native FLAC'.  The transport consists of audio frame headers and footers which contain synchronization patterns, timecodes, and checksums (but notably not frame lengths), and a metadata system.  It is very lightweight and does not support more elaborate transport mechanisms such as multiple logical streams, but it has served its purpose well.<br />
+		<br />
+		The native FLAC transport is not a transport "layer" in the way of standard codec design because it cannot be entirely separated from the payload.  Though the metadata system can be separated, the frame header includes both data that belongs in the transport (sync pattern, timecode, checksum) and data that belongs in the compressed packets (audio parameters like channel assignments, sample rate, etc).<br />
+		<br />
+		This presents a problem when trying to encapsulate FLAC in other true transport layers; the choice has to be made between redundancy and complexity.  In pursuit of correctness, a mapping could be created that removed from native FLAC the transport data, and merged the remaining frame header information into the audio packets.  The disadvantage is that current native FLAC decoder software could not be used to decode because of the tight coupling with the transport.  Either a separate decoding implementation would have to be created and maintained, or an Ogg FLAC decoder would have to synthesize native FLAC frames from Ogg FLAC packets and feed them to a native FLAC decoder.<br />
+		<br />
+		The alternative is to treat native FLAC frames as Ogg packets and accept the transport redundancy.  It turns out that this is not much of a penalty; a maximum of 12 bytes per frame will be wasted.  Given the common case of stereo CD audio encoded with a blocksize of 4096 samples, a compressed frame will be 4-16 Kbytes.  The redundancy amounts to a fraction of a percent.<br />
+		<br />
+		In the interest of simplicity and expediency, the second method was chosen for the first official FLAC-&gt;Ogg mapping.  A mapping version is included in the first packet so that a less redundant mapping can be defined in the future.<br />
+		<br />
+		It should also be noted that support for encapsulating FLAC in Ogg has been present in the FLAC tools since version 1.0.1.  However, the mappings used were never formalized and have insurmountable problems.  For that reason, Ogg FLAC streams created with <span class="commandname">flac</span> versions before 1.1.1 should be decoded and re-encoded with <span class="commandname">flac</span> 1.1.1 or later (<span class="commandname">flac</span> 1.1.1 can decode all previous Ogg FLAC files, but files made prior to 1.1.0 don't support seeking).  Since the support for Ogg FLAC before FLAC 1.1.1 was limited, we hope this will not result in too much inconvenience.<br />
+		<br />
+		Version 1.0 of the FLAC-to-Ogg mapping then is a simple identifying header followed by pure native FLAC data, as follows:
+		<ul>
+			<li>
+				The first packet of a stream consists of:
+				<ul>
+					<li>The one-byte packet type 0x7F</li>
+					<li>The four-byte ASCII signature "FLAC", i.e. 0x46, 0x4C, 0x41, 0x43</li>
+					<li>A one-byte binary major version number for the mapping, e.g. 0x01 for mapping version 1.0</li>
+					<li>A one-byte binary minor version number for the mapping, e.g. 0x00 for mapping version 1.0</li>
+					<li>A two-byte, big-endian binary number signifying the number of header (non-audio) packets, not including this one.  This number may be zero (0x0000) to signify 'unknown' but be aware that some decoders may not be able to handle such streams.</li>
+					<li>The four-byte ASCII native FLAC signature "fLaC" according to the <a href="format.html#stream">FLAC format specification</a></li>
+					<li>The <a href="format.html#metadata_block">STREAMINFO</a> metadata block for the stream.</li>
+				</ul>
+				This first packet is the only packet in the first page of the stream.  This results in a first Ogg page of exactly 79 bytes at the very beginning of the logical stream.
+			</li>
+			<li>
+				This first page is marked 'beginning of stream' in the page flags.
+			</li>
+			<li>
+				The first packet is followed by one or more header packets.  Each such packet will contain a single <a href="format.html#metadata_block">native FLAC metadata block</a>.  The first of these must be a VORBIS_COMMENT block.  These packets may span page boundaries but the last will finish the page on which it ends, so that the first audio packet begins a page.  The first byte of these metadata packets serves also as the packet type, and has a legal range of (0x01-0x7E,0x81-0xFE).
+			</li>
+			<li>
+				The granule position of these first pages containing only headers is zero.
+			</li>
+			<li>
+				The first audio packet of the logical stream begins a fresh Ogg page.
+			</li>
+			<li>
+				Native FLAC audio frames appear as subsequent packets in the stream.  Each packet corresponds to one FLAC audio frame.  The first byte of each packet serves as the packet type.  Since audio packets are native FLAC frames, this first byte will be always 0xFF according to the <a href="format.html#frame_header">native FLAC format specification</a>.
+			</li>
+			<li>
+				The last page is marked 'end of stream' in the page flags.
+			</li>
+			<li>
+				FLAC packets may span page boundaries.
+			</li>
+			<li>
+				The granule position of pages containing FLAC audio follows the same semantics as that for Ogg-encapsulated Vorbis as described <a href="http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-126000A">here</a>.
+			</li>
+			<li>
+				Redundant fields in the STREAMINFO packet may be set to zero (indicating "unknown" in native FLAC), which also facilitates single-pass encoding.  These fields are: the minimum and maximum frame sizes, the total samples count, and the MD5 signature.  "Unknown" values for these fields will not prevent a compliant native FLAC or Ogg FLAC decoder from decoding the stream.
+			</li>
+		</ul>
+		It is intended that the first six bytes of any version of FLAC-to-Ogg mapping will share the same structure, namely, the four-byte signature and two-byte version number.<br />
+		<br />
+		There is an implicit hint to the decoder in the mapping version number; mapping versions which share the same major version number should be decodable by decoders of the same major version number, e.g. a 1.x Ogg FLAC decoder should be able to decode any 1.y Ogg FLAC stream, even when x&lt;y.  If a mapping breaks this forward compatibility the major version number will be incremented.
+	</div>
+	<div class="box_footer"></div>
+</div>
+
+
+<div class="copyright">
+	<!-- @@@ oh so hacky -->
+	<table>
+		<tr>
+			<td align="left">
+				Copyright (c) 2004-2009  Josh Coalson
+				<br/>
+				Copyright (c) 2011-2016  Xiph.Org Foundation
+			</td>
+		</tr>
+	</table>
+</div>
+
+</body>
+</html>
diff --git a/doc/isoflac.txt b/doc/isoflac.txt
new file mode 100644
index 0000000..574df9f
--- /dev/null
+++ b/doc/isoflac.txt
@@ -0,0 +1,666 @@
+Encapsulation of FLAC in ISO Base Media File Format
+Version 0.0.4 (draft)
+
+Table of Contents
+1 Scope
+2 Supporting Normative References
+3 Design Rules of Encapsulation
+  3.1 File Type Identification
+  3.2 Overview of Track Structure
+  3.3 Definition of FLAC sample
+        3.3.1 Sample entry format
+        3.3.2 FLAC Specific Box
+        3.3.3 Sample format
+        3.3.4 Duration of FLAC sample
+        3.3.5 Sub-sample
+        3.3.6 Random Access
+            3.3.6.1 Random Access Point
+   3.4 Basic Structure (informative)
+        3.4.1 Initial Movie
+   3.5 Example of Encapsulation (informative)
+4 Acknowledgements
+5 Author's Address
+
+1 Scope
+
+    This document specifies the normative mapping for encapsulation of
+    FLAC coded audio bitstreams in ISO Base Media file format and its
+    derivatives. The encapsulation of FLAC coded bitstreams in
+    QuickTime file format is outside the scope of this specification.
+
+2 Supporting Normative References
+
+    [1] ISO/IEC 14496-12:2012 Corrected version
+
+        Information technology — Coding of audio-visual objects — Part
+        12: ISO base media file format
+
+    [2] ISO/IEC 14496-12:2012/Amd.1:2013
+
+        Information technology — Coding of audio-visual objects — Part
+        12: ISO base media file format AMENDMENT 1: Various
+        enhancements including support for large metadata
+
+    [3] FLAC format specification
+
+        https://xiph.org/flac/format.html
+
+        Definition of the FLAC Audio Codec stream format
+
+    [4] FLAC-in-Ogg mapping specification
+
+        https://xiph.org/flac/ogg_mapping.html
+
+        Ogg Encapsulation for the FLAC Audio Codec
+
+    [5] Matroska specification
+
+3 Design Rules of Encapsulation
+
+    3.1 File Type Identification
+    
+        This specification does not define any brand to declare files
+        which conform to this specification.  Files which conform to
+        this specification shall contain at least one brand which
+        supports the requirements and the requirements described in
+        this clause without contradiction in the compatible brands
+        list of the File Type Box.  The minimal support of the
+        encapsulation of FLAC bitstreams in ISO Base Media file format
+        requires the 'isom' brand.
+        
+    3.2 Overview of Track Structure
+
+        FLAC coded audio shall be encapsulated into the ISO Base
+        Media File Format as media data within an audio track.
+        
+            + The handler_type field in the Handler Reference Box
+              shall be set to 'soun'.
+            
+            + The Media Information Box shall contain the Sound Media
+              Header Box.
+            
+            + The codingname of the sample entry is 'fLaC'.
+            
+                This specification does not define any encapsulation
+                using MP4AudioSampleEntry with objectTypeIndication
+                specified by the MPEG-4 Registration Authority
+                (http://www.mp4ra.org/).  See section 'Sample entry
+                format' for the definition of the sample entry.
+                
+            + The 'dfLa' box is added to the sample entry to convey
+                initializing information for the decoder.
+
+                See section 'FLAC Specific Box' for the definition of
+                the box contents.
+
+            + A FLAC sample is exactly one FLAC frame as described
+                in the format specification[3].  See section
+                'Sample format' for details of the frame contents.
+
+            + Every FLAC sample is a sync sample.  No pre-roll or
+                lapping is required.  See section 'Random Access' for
+                further details.
+
+    3.3 Definition of a FLAC sample
+    
+        3.3.1 Sample entry format
+
+            For any track containing one or more FLAC bitstreams, a
+            sample entry describing the corresponding FLAC bitstream
+            shall be present inside the Sample Table Box. This version
+            of the specification defines only one sample entry format
+            named FLACSampleEntry whose codingname is 'fLaC'.  This
+            sample entry includes exactly one FLAC Specific Box
+            defined in section 'FLAC specific box' as a mandatory box
+            and indicates that FLAC samples described by this sample
+            entry are stored by the sample format described in section
+            'Sample format'.
+
+            The syntax and semantics of the FLACSampleEntry is shown
+            as follows.  The data fields of this box and native
+            FLAC[3] structures encoded within FLAC blocks are both
+            stored in big-endian format, though for purposes of the
+            ISO BMFF container, FLAC native metadata and data blocks
+            are treated as unstructured octet streams.
+ 
+            class FLACSampleEntry() extends AudioSampleEntry ('fLaC'){
+                FLACSpecificBox();
+            }
+
+            The fields of the AudioSampleEntry portion shall be set as
+            follows:
+
+            + channelcount:
+
+                The channelcount field shall be set equal to the
+                channel count specified by the FLAC bitstream's native
+                METADATA_BLOCK_STREAMINFO header as described in [3].
+                Note that the FLAC FRAME_HEADER structure that begins
+                each FLAC sample redundantly encodes channel number;
+                the number of channels declared in each FRAME_HEADER
+                MUST match the number of channels declared here and in
+                the METADATA_BLOCK_STREAMINFO header.
+
+            + samplesize:
+
+                The samplesize field shall be set equal to the bits
+                per sample specified by the FLAC bitstream's native
+                METADATA_BLOCK_STREAMINFO header as described in [3].
+                Note that the FLAC FRAME_HEADER structure that begins
+                each FLAC sample redundantly encodes the number of
+                bits per sample; the bits per sample declared in each
+                FRAME_HEADER MUST match the samplesize declared here
+                and the bits per sample field declared in the
+                METADATA_BLOCK_STREAMINFO header.
+                
+            + samplerate:
+
+                When possible, the samplerate field shall be set
+                equal to the sample rate specified by the FLAC
+                bitstream's native METADATA_BLOCK_STREAMINFO header
+                as described in [3], left-shifted by 16 bits to
+                create the appropriate 16.16 fixed-point
+                representation.
+
+                When the bitstream's native sample rate is greater
+                than the maximum expressible value of 65535 Hz,
+                the samplerate field shall hold the greatest
+                expressible regular division of that rate. I.e.
+                the samplerate field shall hold 48000.0 for
+                native sample rates of 96 and 192 kHz. In the
+                case of unusual sample rates which do not have
+                an expressible regular division, the maximum value
+                of 65535.0 Hz should be used.
+
+                High-rate FLAC bitstreams are common, and the native
+                value from the METADATA_BLOCK_STREAMINFO header in
+                the FLACSpecificBox MUST be read to determine the
+                correct sample rate of the bitstream.
+
+                Note that the FLAC FRAME_HEADER structure that begins
+                each FLAC sample redundantly encodes the sample rate;
+                the sample rate declared in each FRAME_HEADER MUST
+                match the sample rate declared in the
+                METADATA_BLOCK_STREAMINFO header, and here in the
+                AudioSampleEntry portion of the FLACSampleEntry
+                as much as is allowed by the encoding restrictions
+                described above.
+                
+            Finally, the FLACSpecificBox carries codec headers:
+
+            + FLACSpecificBox
+            
+                This box contains initializing information for the
+                decoder as defined in section 'FLAC specific box'.
+
+        3.3.2 FLAC Specific Box
+        
+            Exactly one FLAC Specific Box shall be present in each
+            FLACSampleEntry.  This specification defines version 0
+            of this box.  If incompatible changes occur in future
+            versions of this specification, another version number
+            will be defined.  The data fields of this box and native
+            FLAC[3] structures encoded within FLAC blocks are both
+            stored in big-endian format, though for purposes of the
+            ISO BMFF container, FLAC native metadata and data blocks
+            are treated as unstructured octet streams.
+
+            The syntax and semantics of the FLAC Specific Box is shown
+            as follows.
+
+            class FLACMetadataBlock {
+               unsigned int(1) LastMetadataBlockFlag;
+               unsigned int(7) BlockType;
+               unsigned int(24) Length;
+               unsigned int(8) BlockData[Length];
+            }
+
+            aligned(8) class FLACSpecificBox
+                  extends FullBox('dfLa', version=0, 0){
+               for (i=0; ; i++) { // to end of box
+                  FLACMetadataBlock();
+               }
+            }
+
+            + Version:
+
+                The Version field shall be set to 0.
+
+                In the future versions of this specification, this
+                field may be set to other values. And without support
+                of those values, the reader shall not read the fields
+                after this within the FLACSpecificBox.
+
+            + Flags:
+
+                The Flags field shall be set to 0.
+
+            After the FullBox header, the box contains a sequence of
+            FLAC[3] native-metadata block structures that fill the
+            remainder of the box.
+
+            Each FLACMetadataBlock structure consists of three fields
+            filling a total of four bytes that form a FLAC[3] native
+            METADATA_BLOCK_HEADER, followed by raw octet bytes that
+            comprise the FLAC[3] native METADATA_BLOCK_DATA.
+
+            + LastMetadataBlockFlag:
+
+                The LastMetadataBlockFlag field maps semantically to
+                the FLAC[3] native METADATA_BLOCK_HEADER
+                Last-metadata-block flag as defined in the FLAC[3]
+                file specification.
+                
+                The LastMetadataBlockFlag is set to 1 if this
+                MetadataBlock is the last metadata block in the
+                FLACSpecificBox.  It is set to 0 otherwise.
+               
+            + BlockType:
+
+                The BlockType field maps semantically to the FLAC[3]
+                native METADATA_BLOCK_HEADER BLOCK_TYPE field as
+                defined in the FLAC[3] file specification.
+
+                The BlockType is set to a valid FLAC[3] BLOCK_TYPE
+                value that identifies the type of this native metadata
+                block.  The BlockType of the first FLACMetadataBlock
+                must be set to 0, signifying this is a FLAC[3] native
+                METADATA_BLOCK_STREAMINFO block.
+               
+            + Length:
+
+                The Length field maps semantically to the FLAC[3]
+                native METADATA_BLOCK_HEADER Length field as
+                defined in the FLAC[3] file specification.
+
+                The length field specifies the number of bytes of
+                MetadataBlockData to follow.
+
+            + BlockData
+
+                The BlockData field maps semantically to the FLAC[3]
+                native METADATA_BLOCK_HEADER METADATA_BLOCK_DATA as
+                defined in the FLAC[3] file specification.
+
+            Taken together, the bytes of the FLACMetadataBlock form a
+            complete FLAC[3] native METADATA_BLOCK structure.
+
+            Note that a minimum of a single FLACMetadataBlock,
+            consisting of a FLAC[3] native METADATA_BLOCK_STREAMINFO
+            structure, is required.  Should the FLACSpecificBox
+            contain more than a single FLACMetadataBlock structure,
+            the FLACMetadataBlock containing the FLAC[3] native
+            METADATA_BLOCK_STREAMINFO must occur first in the list.
+
+            Other containers that package FLAC audio streams, such as
+            Ogg[4] and Matroska[5], wrap FLAC[3] native metadata without
+            modification similar to this specification.  When
+            repackaging or remuxing FLAC[3] streams from another
+            format that contains FLAC[3] native metadata into an ISO
+            BMFF file, the complete FLAC[3] native metadata should be
+            preserved in the ISO BMFF stream as described above.  It
+            is also allowed to parse this native metadata and include
+            contextually redundant ISO BMFF-native repackagings and/or
+            reparsings of FLAC[3] native metadata, so long as the
+            native metadata is also preserved.
+
+        3.3.3 Sample format
+        
+            A FLAC sample is exactly one FLAC audio FRAME (as defined
+            in the FLAC[3] file specification) belonging to a FLAC
+            bitstreams. The FLAC sample data begins with a complete
+            FLAC FRAME_HEADER, followed by one FLAC SUBFRAME per
+            channel, any necessary bit padding, and ends with the
+            usual FLAC FRAME_FOOTER.
+
+            Note that the FLAC native FRAME_HEADER structure that
+            begins each FLAC sample redundantly encodes channel count,
+            sample rate, and sample size.  The values of these fields
+            must agree both with the values declared in the FLAC
+            METADATA_BLOCK_STREAMINFO structure as well as the
+            FLACSampleEntry box.
+
+        3.3.4 Duration of a FLAC sample
+
+            The duration of any given FLAC sample is determined by
+            dividing the decoded block size of a FLAC frame, as
+            encoded in the FLAC FRAME's FRAME_HEADER structure, by the
+            value of the timescale field in the Media Header Box.
+            FLAC samples are permitted to have variable durations
+            within a given audio stream.  FLAC does not use padding
+            values.
+
+        3.3.5 Sub-sample
+
+            Sub-samples are not defined for FLAC samples in this
+            specification.
+
+        3.3.6 Random Access
+        
+            This subclause describes the nature of the random access
+            of FLAC sample.
+
+            3.3.6.1 Random Access Point
+            
+                All FLAC samples can be independently decoded
+                i.e. every FLAC sample is a sync sample. The Sync
+                Sample Box shall not be present as long as there are
+                no samples other than FLAC samples in the same
+                track. The sample_is_non_sync_sample field for FLAC
+                samples shall be set to 0.
+
+    3.4 Basic Structure (informative)
+
+        3.4.1 Initial Movie
+        
+            This subclause shows a basic structure of the Movie Box as follows:
+
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |moov|    |    |    |    |    |    |    | Movie Box                    |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |mvhd|    |    |    |    |    |    | Movie Header Box             |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |trak|    |    |    |    |    |    | Track Box                    |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |tkhd|    |    |    |    |    | Track Header Box             |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |edts|*   |    |    |    |    | Edit Box                     |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |elst|*   |    |    |    | Edit List Box                |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |mdia|    |    |    |    |    | Media Box                    |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |mdhd|    |    |    |    | Media Header Box             |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |hdlr|    |    |    |    | Handler Reference Box        |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |minf|    |    |    |    | Media Information Box        |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |smhd|    |    |    | Sound Media Header Box       |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |dinf|    |    |    | Data Information Box         |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |dref|    |    | Data Reference Box           |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |    |url |    | DataEntryUrlBox              |
+            +----+----+----+----+----+----+ or +----+------------------------------+
+            |    |    |    |    |    |    |urn |    | DataEntryUrnBox              |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |stbl|    |    |    | Sample Table                 |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |stsd|    |    | Sample Description Box       |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |    |fLaC|    | FLACSampleEntry              |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |    |    |dfLa| FLAC Specific Box            |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |stts|    |    | Decoding Time to Sample Box  |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |stsc|    |    | Sample To Chunk Box          |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |stsz|    |    | Sample Size Box              |
+            +----+----+----+----+----+ or +----+----+------------------------------+
+            |    |    |    |    |    |stz2|    |    | Compact Sample Size Box      |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |    |    |    |stco|    |    | Chunk Offset Box             |
+            +----+----+----+----+----+ or +----+----+------------------------------+
+            |    |    |    |    |    |co64|    |    | Chunk Large Offset Box       |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |mvex|*   |    |    |    |    |    | Movie Extends Box            |
+            +----+----+----+----+----+----+----+----+------------------------------+
+            |    |    |trex|*   |    |    |    |    | Track Extends Box            |
+            +----+----+----+----+----+----+----+----+------------------------------+
+
+                    Figure 1 - Basic structure of Movie Box
+
+            It is strongly recommended that the order of boxes should
+            follow the above structure.  Boxes marked with an asterisk
+            (*) may or may not be present depending on context.  For
+            most boxes listed above, the definition is as is defined
+            in ISO/IEC 14496-12 [1]. The additional boxes and the
+            additional requirements, restrictions and recommendations
+            to the other boxes are described in this specification.
+            
+    3.5 Example of Encapsulation (informative)
+        [File]
+            size = 17790
+            [ftyp: File Type Box]
+                position = 0
+                size = 24
+                major_brand = mp42 : MP4 version 2
+                minor_version = 0
+                compatible_brands
+                    brand[0] = mp42 : MP4 version 2
+                    brand[1] = isom : ISO Base Media file format
+            [moov: Movie Box]
+                position = 24
+                size = 757
+                [mvhd: Movie Header Box]
+                    position = 32
+                    size = 108
+                    version = 0
+                    flags = 0x000000
+                    creation_time = UTC 2014/12/12, 18:41:19
+                    modification_time = UTC 2014/12/12, 18:41:19
+                    timescale = 48000
+                    duration = 33600 (00:00:00.700)
+                    rate = 1.000000
+                    volume = 1.000000
+                    reserved = 0x0000
+                    reserved = 0x00000000
+                    reserved = 0x00000000
+                    transformation matrix
+                        | a, b, u |   | 1.000000, 0.000000, 0.000000 |
+                        | c, d, v | = | 0.000000, 1.000000, 0.000000 |
+                        | x, y, w |   | 0.000000, 0.000000, 1.000000 |
+                    pre_defined = 0x00000000
+                    pre_defined = 0x00000000
+                    pre_defined = 0x00000000
+                    pre_defined = 0x00000000
+                    pre_defined = 0x00000000
+                    pre_defined = 0x00000000
+                    next_track_ID = 2
+                [iods: Object Descriptor Box]
+                    position = 140
+                    size = 33
+                    version = 0
+                    flags = 0x000000
+                    [tag = 0x10: MP4_IOD]
+                        expandableClassSize = 16
+                        ObjectDescriptorID = 1
+                        URL_Flag = 0
+                        includeInlineProfileLevelFlag = 0
+                        reserved = 0xf
+                        ODProfileLevelIndication = 0xff
+                        sceneProfileLevelIndication = 0xff
+                        audioProfileLevelIndication = 0xfe
+                        visualProfileLevelIndication = 0xff
+                        graphicsProfileLevelIndication = 0xff
+                        [tag = 0x0e: ES_ID_Inc]
+                            expandableClassSize = 4
+                            Track_ID = 1
+                [trak: Track Box]
+                    position = 173
+                    size = 608
+                    [tkhd: Track Header Box]
+                        position = 181
+                        size = 92
+                        version = 0
+                        flags = 0x000007
+                            Track enabled
+                            Track in movie
+                            Track in preview
+                        creation_time = UTC 2014/12/12, 18:41:19
+                        modification_time = UTC 2014/12/12, 18:41:19
+                        track_ID = 1
+                        reserved = 0x00000000
+                        duration = 33600 (00:00:00.700)
+                        reserved = 0x00000000
+                        reserved = 0x00000000
+                        layer = 0
+                        alternate_group = 0
+                        volume = 1.000000
+                        reserved = 0x0000
+                        transformation matrix
+                            | a, b, u |   | 1.000000, 0.000000, 0.000000 |
+                            | c, d, v | = | 0.000000, 1.000000, 0.000000 |
+                            | x, y, w |   | 0.000000, 0.000000, 1.000000 |
+                        width = 0.000000
+                        height = 0.000000
+                    [mdia: Media Box]
+                        position = 273
+                        size = 472
+                        [mdhd: Media Header Box]
+                            position = 281
+                            size = 32
+                            version = 0
+                            flags = 0x000000
+                            creation_time = UTC 2014/12/12, 18:41:19
+                            modification_time = UTC 2014/12/12, 18:41:19
+                            timescale = 48000
+                            duration = 34560 (00:00:00.720)
+                            language = und
+                            pre_defined = 0x0000
+                        [hdlr: Handler Reference Box]
+                            position = 313
+                            size = 51
+                            version = 0
+                            flags = 0x000000
+                            pre_defined = 0x00000000
+                            handler_type = soun
+                            reserved = 0x00000000
+                            reserved = 0x00000000
+                            reserved = 0x00000000
+                            name = Xiph Audio Handler
+                        [minf: Media Information Box]
+                            position = 364
+                            size = 381
+                            [smhd: Sound Media Header Box]
+                                position = 372
+                                size = 16
+                                version = 0
+                                flags = 0x000000
+                                balance = 0.000000
+                                reserved = 0x0000
+                            [dinf: Data Information Box]
+                                position = 388
+                                size = 36
+                                [dref: Data Reference Box]
+                                    position = 396
+                                    size = 28
+                                    version = 0
+                                    flags = 0x000000
+                                    entry_count = 1
+                                    [url : Data Entry Url Box]
+                                        position = 412
+                                        size = 12
+                                        version = 0
+                                        flags = 0x000001
+                                        location = in the same file
+                            [stbl: Sample Table Box]
+                                position = 424
+                                size = 321
+                                [stsd: Sample Description Box]
+                                    position = 432
+                                    size = 79
+                                    version = 0
+                                    flags = 0x000000
+                                    entry_count = 1
+                                    [fLaC: Audio Description]
+                                        position = 448
+                                        size = 63
+                                        reserved = 0x000000000000
+                                        data_reference_index = 1
+                                        reserved = 0x0000
+                                        reserved = 0x0000
+                                        reserved = 0x00000000
+                                        channelcount = 2
+                                        samplesize = 16
+                                        pre_defined = 0
+                                        reserved = 0
+                                        samplerate = 48000.000000
+                                        [dfLa: FLAC Specific Box]
+                                            position = 484
+                                            size = 50
+                                            version = 0
+                                            flags = 0x000000
+                                            [FLACMetadataBlock]
+                                                LastMetadataBlockFlag = 1
+                                                BlockType = 0
+                                                Length = 34
+                                                BlockData[34];
+                                [stts: Decoding Time to Sample Box]
+                                    position = 492
+                                    size = 24
+                                    version = 0
+                                    flags = 0x000000
+                                    entry_count = 1
+                                    entry[0]
+                                        sample_count = 18
+                                        sample_delta = 1920
+                                [stsc: Sample To Chunk Box]
+                                    position = 516
+                                    size = 40
+                                    version = 0
+                                    flags = 0x000000
+                                    entry_count = 2
+                                    entry[0]
+                                        first_chunk = 1
+                                        samples_per_chunk = 13
+                                        sample_description_index = 1
+                                    entry[1]
+                                        first_chunk = 2
+                                        samples_per_chunk = 5
+                                        sample_description_index = 1
+                                [stsz: Sample Size Box]
+                                    position = 556
+                                    size = 92
+                                    version = 0
+                                    flags = 0x000000
+                                    sample_size = 0 (variable)
+                                    sample_count = 18
+                                    entry_size[0] = 977
+                                    entry_size[1] = 938
+                                    entry_size[2] = 939
+                                    entry_size[3] = 938
+                                    entry_size[4] = 934
+                                    entry_size[5] = 945
+                                    entry_size[6] = 948
+                                    entry_size[7] = 956
+                                    entry_size[8] = 955
+                                    entry_size[9] = 930
+                                    entry_size[10] = 933
+                                    entry_size[11] = 934
+                                    entry_size[12] = 972
+                                    entry_size[13] = 977
+                                    entry_size[14] = 958
+                                    entry_size[15] = 949
+                                    entry_size[16] = 962
+                                    entry_size[17] = 848
+                                [stco: Chunk Offset Box]
+                                    position = 648
+                                    size = 24
+                                    version = 0
+                                    flags = 0x000000
+                                    entry_count = 2
+                                    chunk_offset[0] = 686
+                                    chunk_offset[1] = 12985
+            [free: Free Space Box]
+                position = 672
+                size = 8
+            [mdat: Media Data Box]
+                position = 680
+                size = 17001
+
+4 Acknowledgements
+
+    This spec draws heavily from the Opus-in-ISOBMFF specification
+    work done by Yusuke Nakamura <muken.the.vfrmaniac |at| gmail.com>
+
+    Thank you to Tim Terriberry, David Evans, and Yusuke Nakamura
+    for valuable feedback. Thank you to Ralph Giles for editorial
+    help.
+
+5 Author Address
+
+    Monty Montgomery <cmontgomery@mozilla.com>
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..ed18e3b
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_subdirectory("c/decode/file")
+add_subdirectory("c/encode/file")
+
+if(BUILD_CXXLIBS)
+    add_subdirectory("cpp/decode/file")
+    add_subdirectory("cpp/encode/file")
+endif()
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..9ae4f15
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,28 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+if FLaC__WITH_CPPLIBS
+CPPLIBS_DIRS = cpp
+endif
+
+SUBDIRS = c $(CPPLIBS_DIRS)
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	README
diff --git a/examples/Makefile.lite b/examples/Makefile.lite
new file mode 100644
index 0000000..f805a3e
--- /dev/null
+++ b/examples/Makefile.lite
@@ -0,0 +1,50 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+.PHONY: all example_c_decode_file example_c_encode_file example_cpp_decode_file example_cpp_encode_file
+all: example_c_decode_file example_c_encode_file example_cpp_decode_file example_cpp_encode_file
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+example_c_decode_file:
+	(cd c/decode/file && $(MAKE) -f Makefile.lite $(CONFIG))
+
+example_c_encode_file:
+	(cd c/encode/file && $(MAKE) -f Makefile.lite $(CONFIG))
+
+example_cpp_decode_file:
+	(cd cpp/decode/file && $(MAKE) -f Makefile.lite $(CONFIG))
+
+example_cpp_encode_file:
+	(cd cpp/encode/file && $(MAKE) -f Makefile.lite $(CONFIG))
+
+clean:
+	-(cd c/decode/file && $(MAKE) -f Makefile.lite clean)
+	-(cd c/encode/file && $(MAKE) -f Makefile.lite clean)
+	-(cd cpp/decode/file && $(MAKE) -f Makefile.lite clean)
+	-(cd cpp/encode/file && $(MAKE) -f Makefile.lite clean)
diff --git a/examples/README b/examples/README
new file mode 100644
index 0000000..2da7bd6
--- /dev/null
+++ b/examples/README
@@ -0,0 +1,12 @@
+Here are several small example programs that use the libraries in different
+ways.
+
+The "c" directory has programs that are all in C and use libFLAC.
+
+The "cpp" directory has analogous programs that are all in C++ and use libFLAC++.
+
+The programs are:
+c/decode/file/ - example_c_decode_file - Simple FLAC file decoder using libFLAC
+c/encode/file/ - example_c_encode_file - Simple FLAC file encoder using libFLAC
+cpp/decode/file/ - example_cpp_decode_file - Simple FLAC file decoder using libFLAC++
+cpp/encode/file/ - example_cpp_encode_file - Simple FLAC file encoder using libFLAC++
diff --git a/examples/c/Makefile.am b/examples/c/Makefile.am
new file mode 100644
index 0000000..e44ad01
--- /dev/null
+++ b/examples/c/Makefile.am
@@ -0,0 +1,19 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = decode encode
diff --git a/examples/c/decode/Makefile.am b/examples/c/decode/Makefile.am
new file mode 100644
index 0000000..2e103e4
--- /dev/null
+++ b/examples/c/decode/Makefile.am
@@ -0,0 +1,19 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = file
diff --git a/examples/c/decode/file/CMakeLists.txt b/examples/c/decode/file/CMakeLists.txt
new file mode 100644
index 0000000..53a2991
--- /dev/null
+++ b/examples/c/decode/file/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(decode_file main.c)
+target_link_libraries(decode_file FLAC)
diff --git a/examples/c/decode/file/Makefile.am b/examples/c/decode/file/Makefile.am
new file mode 100644
index 0000000..da1bae1
--- /dev/null
+++ b/examples/c/decode/file/Makefile.am
@@ -0,0 +1,33 @@
+#  example_c_decode_file - Simple FLAC file decoder using libFLAC
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	example_c_decode_file.vcproj \
+	example_c_decode_file.vcxproj \
+	example_c_decode_file.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+noinst_PROGRAMS = example_c_decode_file
+example_c_decode_file_LDADD = \
+	$(top_builddir)/src/libFLAC/libFLAC.la
+
+example_c_decode_file_SOURCES = main.c
+
+CLEANFILES = example_c_decode_file.exe
diff --git a/examples/c/decode/file/Makefile.lite b/examples/c/decode/file/Makefile.lite
new file mode 100644
index 0000000..16d5268
--- /dev/null
+++ b/examples/c/decode/file/Makefile.lite
@@ -0,0 +1,42 @@
+#  example_c_decode_file - Simple FLAC file decoder using libFLAC
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../../../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = example_c_decode_file
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lFLAC $(OGG_LIBS) -lm
+endif
+
+SRCS_C = main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/examples/c/decode/file/example_c_decode_file.vcproj b/examples/c/decode/file/example_c_decode_file.vcproj
new file mode 100644
index 0000000..ddd20bc
--- /dev/null
+++ b/examples/c/decode/file/example_c_decode_file.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="example_c_decode_file"

+	ProjectGUID="{4cefbd00-c215-11db-8314-0800200c9a66}"

+	RootNamespace="example_c_decode_file"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories="..\..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{39992580-89DB-4b41-8E8B-625F9E28BEBF}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC727F1-C7A5-1376-A061-2AF2D742A2F0}"

+			>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/examples/c/decode/file/example_c_decode_file.vcxproj b/examples/c/decode/file/example_c_decode_file.vcxproj
new file mode 100644
index 0000000..db14265
--- /dev/null
+++ b/examples/c/decode/file/example_c_decode_file.vcxproj
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbd00-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>example_c_decode_file</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\..\..\src\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/examples/c/decode/file/example_c_decode_file.vcxproj.filters b/examples/c/decode/file/example_c_decode_file.vcxproj.filters
new file mode 100644
index 0000000..a700a4f
--- /dev/null
+++ b/examples/c/decode/file/example_c_decode_file.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{39992580-89DB-4b41-8E8B-625F9E28BEBF}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC727F1-C7A5-1376-A061-2AF2D742A2F0}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/examples/c/decode/file/main.c b/examples/c/decode/file/main.c
new file mode 100644
index 0000000..8b3710b
--- /dev/null
+++ b/examples/c/decode/file/main.c
@@ -0,0 +1,200 @@
+/* example_c_decode_file - Simple FLAC file decoder using libFLAC
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * This example shows how to use libFLAC to decode a FLAC file to a WAVE
+ * file.  It only supports 16-bit stereo files.
+ *
+ * Complete API documentation can be found at:
+ *   http://xiph.org/flac/api/
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "share/compat.h"
+#include "FLAC/stream_decoder.h"
+
+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__uint64 total_samples = 0;
+static unsigned sample_rate = 0;
+static unsigned channels = 0;
+static unsigned bps = 0;
+
+static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+	return
+		fputc(x, f) != EOF &&
+		fputc(x >> 8, f) != EOF
+	;
+}
+
+static FLAC__bool write_little_endian_int16(FILE *f, FLAC__int16 x)
+{
+	return write_little_endian_uint16(f, (FLAC__uint16)x);
+}
+
+static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+	return
+		fputc(x, f) != EOF &&
+		fputc(x >> 8, f) != EOF &&
+		fputc(x >> 16, f) != EOF &&
+		fputc(x >> 24, f) != EOF
+	;
+}
+
+int main(int argc, char *argv[])
+{
+	FLAC__bool ok = true;
+	FLAC__StreamDecoder *decoder = 0;
+	FLAC__StreamDecoderInitStatus init_status;
+	FILE *fout;
+
+	if(argc != 3) {
+		fprintf(stderr, "usage: %s infile.flac outfile.wav\n", argv[0]);
+		return 1;
+	}
+
+	if((fout = fopen(argv[2], "wb")) == NULL) {
+		fprintf(stderr, "ERROR: opening %s for output\n", argv[2]);
+		return 1;
+	}
+
+	if((decoder = FLAC__stream_decoder_new()) == NULL) {
+		fprintf(stderr, "ERROR: allocating decoder\n");
+		fclose(fout);
+		return 1;
+	}
+
+	(void)FLAC__stream_decoder_set_md5_checking(decoder, true);
+
+	init_status = FLAC__stream_decoder_init_file(decoder, argv[1], write_callback, metadata_callback, error_callback, /*client_data=*/fout);
+	if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]);
+		ok = false;
+	}
+
+	if(ok) {
+		ok = FLAC__stream_decoder_process_until_end_of_stream(decoder);
+		fprintf(stderr, "decoding: %s\n", ok? "succeeded" : "FAILED");
+		fprintf(stderr, "   state: %s\n", FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(decoder)]);
+	}
+
+	FLAC__stream_decoder_delete(decoder);
+	fclose(fout);
+
+	return 0;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	FILE *f = (FILE*)client_data;
+	const FLAC__uint32 total_size = (FLAC__uint32)(total_samples * channels * (bps/8));
+	size_t i;
+
+	(void)decoder;
+
+	if(total_samples == 0) {
+		fprintf(stderr, "ERROR: this example only works for FLAC files that have a total_samples count in STREAMINFO\n");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+	if(channels != 2 || bps != 16) {
+		fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+	if(frame->header.channels != 2) {
+		fprintf(stderr, "ERROR: This frame contains %u channels (should be 2)\n", frame->header.channels);
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+	if(buffer [0] == NULL) {
+		fprintf(stderr, "ERROR: buffer [0] is NULL\n");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+	if(buffer [1] == NULL) {
+		fprintf(stderr, "ERROR: buffer [1] is NULL\n");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	/* write WAVE header before we write the first frame */
+	if(frame->header.number.sample_number == 0) {
+		if(
+			fwrite("RIFF", 1, 4, f) < 4 ||
+			!write_little_endian_uint32(f, total_size + 36) ||
+			fwrite("WAVEfmt ", 1, 8, f) < 8 ||
+			!write_little_endian_uint32(f, 16) ||
+			!write_little_endian_uint16(f, 1) ||
+			!write_little_endian_uint16(f, (FLAC__uint16)channels) ||
+			!write_little_endian_uint32(f, sample_rate) ||
+			!write_little_endian_uint32(f, sample_rate * channels * (bps/8)) ||
+			!write_little_endian_uint16(f, (FLAC__uint16)(channels * (bps/8))) || /* block align */
+			!write_little_endian_uint16(f, (FLAC__uint16)bps) ||
+			fwrite("data", 1, 4, f) < 4 ||
+			!write_little_endian_uint32(f, total_size)
+		) {
+			fprintf(stderr, "ERROR: write error\n");
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+
+	/* write decoded PCM samples */
+	for(i = 0; i < frame->header.blocksize; i++) {
+		if(
+			!write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) ||  /* left channel */
+			!write_little_endian_int16(f, (FLAC__int16)buffer[1][i])     /* right channel */
+		) {
+			fprintf(stderr, "ERROR: write error\n");
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	(void)decoder, (void)client_data;
+
+	/* print some stats */
+	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		/* save for later */
+		total_samples = metadata->data.stream_info.total_samples;
+		sample_rate = metadata->data.stream_info.sample_rate;
+		channels = metadata->data.stream_info.channels;
+		bps = metadata->data.stream_info.bits_per_sample;
+
+		fprintf(stderr, "sample rate    : %u Hz\n", sample_rate);
+		fprintf(stderr, "channels       : %u\n", channels);
+		fprintf(stderr, "bits per sample: %u\n", bps);
+		fprintf(stderr, "total samples  : %" PRIu64 "\n", total_samples);
+	}
+}
+
+void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	(void)decoder, (void)client_data;
+
+	fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
+}
diff --git a/examples/c/encode/Makefile.am b/examples/c/encode/Makefile.am
new file mode 100644
index 0000000..2e103e4
--- /dev/null
+++ b/examples/c/encode/Makefile.am
@@ -0,0 +1,19 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = file
diff --git a/examples/c/encode/file/CMakeLists.txt b/examples/c/encode/file/CMakeLists.txt
new file mode 100644
index 0000000..4b7d4c2
--- /dev/null
+++ b/examples/c/encode/file/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(encode_file main.c)
+target_link_libraries(encode_file FLAC)
diff --git a/examples/c/encode/file/Makefile.am b/examples/c/encode/file/Makefile.am
new file mode 100644
index 0000000..17a4491
--- /dev/null
+++ b/examples/c/encode/file/Makefile.am
@@ -0,0 +1,35 @@
+#  example_c_encode_file - Simple FLAC file encoder using libFLAC
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	example_c_encode_file.vcproj \
+	example_c_encode_file.vcxproj \
+	example_c_encode_file.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+noinst_PROGRAMS = example_c_encode_file
+example_c_encode_file_LDADD = \
+	$(top_builddir)/src/libFLAC/libFLAC.la \
+	@OGG_LIBS@ \
+	-lm
+
+example_c_encode_file_SOURCES = main.c
+
+CLEANFILES = example_c_encode_file.exe
diff --git a/examples/c/encode/file/Makefile.lite b/examples/c/encode/file/Makefile.lite
new file mode 100644
index 0000000..1530af9
--- /dev/null
+++ b/examples/c/encode/file/Makefile.lite
@@ -0,0 +1,42 @@
+#  example_c_encode_file - Simple FLAC file encoder using libFLAC
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../../../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = example_c_encode_file
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lFLAC $(OGG_LIBS) -lm
+endif
+
+SRCS_C = main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/examples/c/encode/file/example_c_encode_file.vcproj b/examples/c/encode/file/example_c_encode_file.vcproj
new file mode 100644
index 0000000..26f0e9e
--- /dev/null
+++ b/examples/c/encode/file/example_c_encode_file.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="example_c_encode_file"

+	ProjectGUID="{4cefbd01-c215-11db-8314-0800200c9a66}"

+	RootNamespace="example_c_encode_file"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories="..\..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{39992580-89DB-4b41-8E8B-625F9E28BEBF}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC727F1-C7A5-1376-A061-2AF2D742A2F0}"

+			>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/examples/c/encode/file/example_c_encode_file.vcxproj b/examples/c/encode/file/example_c_encode_file.vcxproj
new file mode 100644
index 0000000..edf464b
--- /dev/null
+++ b/examples/c/encode/file/example_c_encode_file.vcxproj
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbd01-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>example_c_encode_file</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\..\..\src\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/examples/c/encode/file/example_c_encode_file.vcxproj.filters b/examples/c/encode/file/example_c_encode_file.vcxproj.filters
new file mode 100644
index 0000000..a700a4f
--- /dev/null
+++ b/examples/c/encode/file/example_c_encode_file.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{39992580-89DB-4b41-8E8B-625F9E28BEBF}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC727F1-C7A5-1376-A061-2AF2D742A2F0}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/examples/c/encode/file/main.c b/examples/c/encode/file/main.c
new file mode 100644
index 0000000..b12d32b
--- /dev/null
+++ b/examples/c/encode/file/main.c
@@ -0,0 +1,171 @@
+/* example_c_encode_file - Simple FLAC file encoder using libFLAC
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * This example shows how to use libFLAC to encode a WAVE file to a FLAC
+ * file.  It only supports 16-bit stereo files in canonical WAVE format.
+ *
+ * Complete API documentation can be found at:
+ *   http://xiph.org/flac/api/
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+#include "FLAC/metadata.h"
+#include "FLAC/stream_encoder.h"
+
+static void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+
+#define READSIZE 1024
+
+static unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
+static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */
+static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
+
+int main(int argc, char *argv[])
+{
+	FLAC__bool ok = true;
+	FLAC__StreamEncoder *encoder = 0;
+	FLAC__StreamEncoderInitStatus init_status;
+	FLAC__StreamMetadata *metadata[2];
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+	FILE *fin;
+	unsigned sample_rate = 0;
+	unsigned channels = 0;
+	unsigned bps = 0;
+
+	if(argc != 3) {
+		fprintf(stderr, "usage: %s infile.wav outfile.flac\n", argv[0]);
+		return 1;
+	}
+
+	if((fin = fopen(argv[1], "rb")) == NULL) {
+		fprintf(stderr, "ERROR: opening %s for output\n", argv[1]);
+		return 1;
+	}
+
+	/* read wav header and validate it */
+	if(
+		fread(buffer, 1, 44, fin) != 44 ||
+		memcmp(buffer, "RIFF", 4) ||
+		memcmp(buffer+8, "WAVEfmt \020\000\000\000\001\000\002\000", 16) ||
+		memcmp(buffer+32, "\004\000\020\000data", 8)
+	) {
+		fprintf(stderr, "ERROR: invalid/unsupported WAVE file, only 16bps stereo WAVE in canonical form allowed\n");
+		fclose(fin);
+		return 1;
+	}
+	sample_rate = ((((((unsigned)buffer[27] << 8) | buffer[26]) << 8) | buffer[25]) << 8) | buffer[24];
+	channels = 2;
+	bps = 16;
+	total_samples = (((((((unsigned)buffer[43] << 8) | buffer[42]) << 8) | buffer[41]) << 8) | buffer[40]) / 4;
+
+	/* allocate the encoder */
+	if((encoder = FLAC__stream_encoder_new()) == NULL) {
+		fprintf(stderr, "ERROR: allocating encoder\n");
+		fclose(fin);
+		return 1;
+	}
+
+	ok &= FLAC__stream_encoder_set_verify(encoder, true);
+	ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
+	ok &= FLAC__stream_encoder_set_channels(encoder, channels);
+	ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps);
+	ok &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate);
+	ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples);
+
+	/* now add some metadata; we'll add some tags and a padding block */
+	if(ok) {
+		if(
+			(metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL ||
+			(metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL ||
+			/* there are many tag (vorbiscomment) functions but these are convenient for this particular use: */
+			!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", "Some Artist") ||
+			!FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false) || /* copy=false: let metadata object take control of entry's allocated string */
+			!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "YEAR", "1984") ||
+			!FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false)
+		) {
+			fprintf(stderr, "ERROR: out of memory or tag error\n");
+			ok = false;
+		}
+
+		metadata[1]->length = 1234; /* set the padding length */
+
+		ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2);
+	}
+
+	/* initialize encoder */
+	if(ok) {
+		init_status = FLAC__stream_encoder_init_file(encoder, argv[2], progress_callback, /*client_data=*/NULL);
+		if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+			fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
+			ok = false;
+		}
+	}
+
+	/* read blocks of samples from WAVE file and feed to encoder */
+	if(ok) {
+		size_t left = (size_t)total_samples;
+		while(ok && left) {
+			size_t need = (left>READSIZE? (size_t)READSIZE : (size_t)left);
+			if(fread(buffer, channels*(bps/8), need, fin) != need) {
+				fprintf(stderr, "ERROR: reading from WAVE file\n");
+				ok = false;
+			}
+			else {
+				/* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
+				size_t i;
+				for(i = 0; i < need*channels; i++) {
+					/* inefficient but simple and works on big- or little-endian machines */
+					pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
+				}
+				/* feed samples to encoder */
+				ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, need);
+			}
+			left -= need;
+		}
+	}
+
+	ok &= FLAC__stream_encoder_finish(encoder);
+
+	fprintf(stderr, "encoding: %s\n", ok? "succeeded" : "FAILED");
+	fprintf(stderr, "   state: %s\n", FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder)]);
+
+	/* now that encoding is finished, the metadata can be freed */
+	FLAC__metadata_object_delete(metadata[0]);
+	FLAC__metadata_object_delete(metadata[1]);
+
+	FLAC__stream_encoder_delete(encoder);
+	fclose(fin);
+
+	return 0;
+}
+
+void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
+{
+	(void)encoder, (void)client_data;
+
+	fprintf(stderr, "wrote %" PRIu64 " bytes, %" PRIu64 "/%u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
+}
diff --git a/examples/cpp/Makefile.am b/examples/cpp/Makefile.am
new file mode 100644
index 0000000..e44ad01
--- /dev/null
+++ b/examples/cpp/Makefile.am
@@ -0,0 +1,19 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = decode encode
diff --git a/examples/cpp/decode/Makefile.am b/examples/cpp/decode/Makefile.am
new file mode 100644
index 0000000..2e103e4
--- /dev/null
+++ b/examples/cpp/decode/Makefile.am
@@ -0,0 +1,19 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = file
diff --git a/examples/cpp/decode/file/CMakeLists.txt b/examples/cpp/decode/file/CMakeLists.txt
new file mode 100644
index 0000000..2ce420d
--- /dev/null
+++ b/examples/cpp/decode/file/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(decode_file_cxx main.cpp)
+target_link_libraries(decode_file_cxx FLAC++)
diff --git a/examples/cpp/decode/file/Makefile.am b/examples/cpp/decode/file/Makefile.am
new file mode 100644
index 0000000..bde9cb2
--- /dev/null
+++ b/examples/cpp/decode/file/Makefile.am
@@ -0,0 +1,36 @@
+#  example_cpp_decode_file - Simple FLAC file decoder using libFLAC
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	example_cpp_decode_file.vcproj \
+	example_cpp_decode_file.vcxproj \
+	example_cpp_decode_file.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+noinst_PROGRAMS = example_cpp_decode_file
+example_cpp_decode_file_LDADD = \
+	$(top_builddir)/src/libFLAC++/libFLAC++.la \
+	$(top_builddir)/src/libFLAC/libFLAC.la \
+	@OGG_LIBS@ \
+	-lm
+
+example_cpp_decode_file_SOURCES = main.cpp
+
+CLEANFILES = example_cpp_decode_file.exe
diff --git a/examples/cpp/decode/file/Makefile.lite b/examples/cpp/decode/file/Makefile.lite
new file mode 100644
index 0000000..c835bb4
--- /dev/null
+++ b/examples/cpp/decode/file/Makefile.lite
@@ -0,0 +1,44 @@
+#  example_cpp_decode_file - Simple FLAC file decoder using libFLAC
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../../../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = example_cpp_decode_file
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC++.a $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lFLAC++ -lFLAC $(OGG_LIBS) -lm
+endif
+
+SRCS_CPP = main.cpp
+
+include $(topdir)/build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/examples/cpp/decode/file/example_cpp_decode_file.vcproj b/examples/cpp/decode/file/example_cpp_decode_file.vcproj
new file mode 100644
index 0000000..59e735d
--- /dev/null
+++ b/examples/cpp/decode/file/example_cpp_decode_file.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="example_cpp_decode_file"

+	ProjectGUID="{4cefbe00-c215-11db-8314-0800200c9a66}"

+	RootNamespace="example_cpp_decode_file"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories="..\..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93292580-829B-b441-E8B8-65A95828BEB0}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{9C7247F1-CA27-1761-A016-0F27452AD2F0}"

+			>

+			<File

+				RelativePath=".\main.cpp"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/examples/cpp/decode/file/example_cpp_decode_file.vcxproj b/examples/cpp/decode/file/example_cpp_decode_file.vcxproj
new file mode 100644
index 0000000..6dde67e
--- /dev/null
+++ b/examples/cpp/decode/file/example_cpp_decode_file.vcxproj
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbe00-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>example_cpp_decode_file</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\..\..\src\libFLAC++\libFLAC++_static.vcxproj">

+      <Project>{4cefbc86-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\..\..\..\src\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/examples/cpp/decode/file/example_cpp_decode_file.vcxproj.filters b/examples/cpp/decode/file/example_cpp_decode_file.vcxproj.filters
new file mode 100644
index 0000000..6ff808d
--- /dev/null
+++ b/examples/cpp/decode/file/example_cpp_decode_file.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93292580-829B-b441-E8B8-65A95828BEB0}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{9C7247F1-CA27-1761-A016-0F27452AD2F0}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/examples/cpp/decode/file/main.cpp b/examples/cpp/decode/file/main.cpp
new file mode 100644
index 0000000..02a6339
--- /dev/null
+++ b/examples/cpp/decode/file/main.cpp
@@ -0,0 +1,191 @@
+/* example_cpp_decode_file - Simple FLAC file decoder using libFLAC
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * This example shows how to use libFLAC++ to decode a FLAC file to a WAVE
+ * file.  It only supports 16-bit stereo files.
+ *
+ * Complete API documentation can be found at:
+ *   http://xiph.org/flac/api/
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "FLAC++/decoder.h"
+#include "share/compat.h"
+
+static FLAC__uint64 total_samples = 0;
+static uint32_t sample_rate = 0;
+static uint32_t channels = 0;
+static uint32_t bps = 0;
+
+static bool write_little_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+	return
+		fputc(x, f) != EOF &&
+		fputc(x >> 8, f) != EOF
+	;
+}
+
+static bool write_little_endian_int16(FILE *f, FLAC__int16 x)
+{
+	return write_little_endian_uint16(f, (FLAC__uint16)x);
+}
+
+static bool write_little_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+	return
+		fputc(x, f) != EOF &&
+		fputc(x >> 8, f) != EOF &&
+		fputc(x >> 16, f) != EOF &&
+		fputc(x >> 24, f) != EOF
+	;
+}
+
+class OurDecoder: public FLAC::Decoder::File {
+public:
+	OurDecoder(FILE *f_): FLAC::Decoder::File(), f(f_) { }
+protected:
+	FILE *f;
+
+	virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+	virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+	virtual void error_callback(::FLAC__StreamDecoderErrorStatus status);
+private:
+	OurDecoder(const OurDecoder&);
+	OurDecoder&operator=(const OurDecoder&);
+};
+
+int main(int argc, char *argv[])
+{
+	bool ok = true;
+	FILE *fout;
+
+	if(argc != 3) {
+		fprintf(stderr, "usage: %s infile.flac outfile.wav\n", argv[0]);
+		return 1;
+	}
+
+	if((fout = fopen(argv[2], "wb")) == NULL) {
+		fprintf(stderr, "ERROR: opening %s for output\n", argv[2]);
+		return 1;
+	}
+
+	OurDecoder decoder(fout);
+
+	if(!decoder) {
+		fprintf(stderr, "ERROR: allocating decoder\n");
+		fclose(fout);
+		return 1;
+	}
+
+	(void)decoder.set_md5_checking(true);
+
+	FLAC__StreamDecoderInitStatus init_status = decoder.init(argv[1]);
+	if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]);
+		ok = false;
+	}
+
+	if(ok) {
+		ok = decoder.process_until_end_of_stream();
+		fprintf(stderr, "decoding: %s\n", ok? "succeeded" : "FAILED");
+		fprintf(stderr, "   state: %s\n", decoder.get_state().resolved_as_cstring(decoder));
+	}
+
+	fclose(fout);
+
+	return 0;
+}
+
+::FLAC__StreamDecoderWriteStatus OurDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+	const FLAC__uint32 total_size = (FLAC__uint32)(total_samples * channels * (bps/8));
+	size_t i;
+
+	if(total_samples == 0) {
+		fprintf(stderr, "ERROR: this example only works for FLAC files that have a total_samples count in STREAMINFO\n");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+	if(channels != 2 || bps != 16) {
+		fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	/* write WAVE header before we write the first frame */
+	if(frame->header.number.sample_number == 0) {
+		if(
+			fwrite("RIFF", 1, 4, f) < 4 ||
+			!write_little_endian_uint32(f, total_size + 36) ||
+			fwrite("WAVEfmt ", 1, 8, f) < 8 ||
+			!write_little_endian_uint32(f, 16) ||
+			!write_little_endian_uint16(f, 1) ||
+			!write_little_endian_uint16(f, (FLAC__uint16)channels) ||
+			!write_little_endian_uint32(f, sample_rate) ||
+			!write_little_endian_uint32(f, sample_rate * channels * (bps/8)) ||
+			!write_little_endian_uint16(f, (FLAC__uint16)(channels * (bps/8))) || /* block align */
+			!write_little_endian_uint16(f, (FLAC__uint16)bps) ||
+			fwrite("data", 1, 4, f) < 4 ||
+			!write_little_endian_uint32(f, total_size)
+		) {
+			fprintf(stderr, "ERROR: write error\n");
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+
+	/* write decoded PCM samples */
+	for(i = 0; i < frame->header.blocksize; i++) {
+		if(
+			!write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) ||  /* left channel */
+			!write_little_endian_int16(f, (FLAC__int16)buffer[1][i])     /* right channel */
+		) {
+			fprintf(stderr, "ERROR: write error\n");
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void OurDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+	/* print some stats */
+	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		/* save for later */
+		total_samples = metadata->data.stream_info.total_samples;
+		sample_rate = metadata->data.stream_info.sample_rate;
+		channels = metadata->data.stream_info.channels;
+		bps = metadata->data.stream_info.bits_per_sample;
+
+		fprintf(stderr, "sample rate    : %u Hz\n", sample_rate);
+		fprintf(stderr, "channels       : %u\n", channels);
+		fprintf(stderr, "bits per sample: %u\n", bps);
+		fprintf(stderr, "total samples  : %" PRIu64 "\n", total_samples);
+	}
+}
+
+void OurDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+	fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
+}
diff --git a/examples/cpp/encode/Makefile.am b/examples/cpp/encode/Makefile.am
new file mode 100644
index 0000000..2e103e4
--- /dev/null
+++ b/examples/cpp/encode/Makefile.am
@@ -0,0 +1,19 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = file
diff --git a/examples/cpp/encode/file/CMakeLists.txt b/examples/cpp/encode/file/CMakeLists.txt
new file mode 100644
index 0000000..2617876
--- /dev/null
+++ b/examples/cpp/encode/file/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(encode_file_cxx main.cpp)
+target_link_libraries(encode_file_cxx FLAC++)
diff --git a/examples/cpp/encode/file/Makefile.am b/examples/cpp/encode/file/Makefile.am
new file mode 100644
index 0000000..598c765
--- /dev/null
+++ b/examples/cpp/encode/file/Makefile.am
@@ -0,0 +1,36 @@
+#  example_cpp_encode_file - Simple FLAC file encoder using libFLAC
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	example_cpp_encode_file.vcproj \
+	example_cpp_encode_file.vcxproj \
+	example_cpp_encode_file.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+noinst_PROGRAMS = example_cpp_encode_file
+example_cpp_encode_file_LDADD = \
+	$(top_builddir)/src/libFLAC++/libFLAC++.la \
+	$(top_builddir)/src/libFLAC/libFLAC.la \
+	@OGG_LIBS@ \
+	-lm
+
+example_cpp_encode_file_SOURCES = main.cpp
+
+CLEANFILES = example_cpp_encode_file.exe
diff --git a/examples/cpp/encode/file/Makefile.lite b/examples/cpp/encode/file/Makefile.lite
new file mode 100644
index 0000000..982a033
--- /dev/null
+++ b/examples/cpp/encode/file/Makefile.lite
@@ -0,0 +1,44 @@
+#  example_cpp_encode_file - Simple FLAC file encoder using libFLAC
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../../../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = example_cpp_encode_file
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC++.a $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lFLAC++ -lFLAC $(OGG_LIBS) -lm
+endif
+
+SRCS_CPP = main.cpp
+
+include $(topdir)/build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/examples/cpp/encode/file/example_cpp_encode_file.vcproj b/examples/cpp/encode/file/example_cpp_encode_file.vcproj
new file mode 100644
index 0000000..f81949f
--- /dev/null
+++ b/examples/cpp/encode/file/example_cpp_encode_file.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="example_cpp_encode_file"

+	ProjectGUID="{4cefbe01-c215-11db-8314-0800200c9a66}"

+	RootNamespace="example_cpp_encode_file"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories="..\..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93292580-829B-b441-E8B8-65A95828BEB0}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{9C7247F1-CA27-1761-A016-0F27452AD2F0}"

+			>

+			<File

+				RelativePath=".\main.cpp"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/examples/cpp/encode/file/example_cpp_encode_file.vcxproj b/examples/cpp/encode/file/example_cpp_encode_file.vcxproj
new file mode 100644
index 0000000..271b50a
--- /dev/null
+++ b/examples/cpp/encode/file/example_cpp_encode_file.vcxproj
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbe01-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>example_cpp_encode_file</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\..\..\src\libFLAC++\libFLAC++_static.vcxproj">

+      <Project>{4cefbc86-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\..\..\..\src\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/examples/cpp/encode/file/example_cpp_encode_file.vcxproj.filters b/examples/cpp/encode/file/example_cpp_encode_file.vcxproj.filters
new file mode 100644
index 0000000..6ff808d
--- /dev/null
+++ b/examples/cpp/encode/file/example_cpp_encode_file.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93292580-829B-b441-E8B8-65A95828BEB0}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{9C7247F1-CA27-1761-A016-0F27452AD2F0}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/examples/cpp/encode/file/main.cpp b/examples/cpp/encode/file/main.cpp
new file mode 100644
index 0000000..7d44b87
--- /dev/null
+++ b/examples/cpp/encode/file/main.cpp
@@ -0,0 +1,176 @@
+/* example_cpp_encode_file - Simple FLAC file encoder using libFLAC
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * This example shows how to use libFLAC++ to encode a WAVE file to a FLAC
+ * file.  It only supports 16-bit stereo files in canonical WAVE format.
+ *
+ * Complete API documentation can be found at:
+ *   http://xiph.org/flac/api/
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FLAC++/metadata.h"
+#include "FLAC++/encoder.h"
+#include "share/compat.h"
+
+#include <cstring>
+
+class OurEncoder: public FLAC::Encoder::File {
+public:
+	OurEncoder(): FLAC::Encoder::File() { }
+protected:
+	virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate);
+};
+
+#define READSIZE 1024
+
+static uint32_t total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
+static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */
+static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
+
+int main(int argc, char *argv[])
+{
+	bool ok = true;
+	OurEncoder encoder;
+	FLAC__StreamEncoderInitStatus init_status;
+	FLAC__StreamMetadata *metadata[2];
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+	FILE *fin;
+	uint32_t sample_rate = 0;
+	uint32_t channels = 0;
+	uint32_t bps = 0;
+
+	if(argc != 3) {
+		fprintf(stderr, "usage: %s infile.wav outfile.flac\n", argv[0]);
+		return 1;
+	}
+
+	if((fin = fopen(argv[1], "rb")) == NULL) {
+		fprintf(stderr, "ERROR: opening %s for output\n", argv[1]);
+		return 1;
+	}
+
+	/* read wav header and validate it */
+	if(
+		fread(buffer, 1, 44, fin) != 44 ||
+		memcmp(buffer, "RIFF", 4) ||
+		memcmp(buffer+8, "WAVEfmt \020\000\000\000\001\000\002\000", 16) ||
+		memcmp(buffer+32, "\004\000\020\000data", 8)
+	) {
+		fprintf(stderr, "ERROR: invalid/unsupported WAVE file, only 16bps stereo WAVE in canonical form allowed\n");
+		fclose(fin);
+		return 1;
+	}
+	sample_rate = ((((((uint32_t)buffer[27] << 8) | buffer[26]) << 8) | buffer[25]) << 8) | buffer[24];
+	channels = 2;
+	bps = 16;
+	total_samples = (((((((uint32_t)buffer[43] << 8) | buffer[42]) << 8) | buffer[41]) << 8) | buffer[40]) / 4;
+
+	/* check the encoder */
+	if(!encoder) {
+		fprintf(stderr, "ERROR: allocating encoder\n");
+		fclose(fin);
+		return 1;
+	}
+
+	ok &= encoder.set_verify(true);
+	ok &= encoder.set_compression_level(5);
+	ok &= encoder.set_channels(channels);
+	ok &= encoder.set_bits_per_sample(bps);
+	ok &= encoder.set_sample_rate(sample_rate);
+	ok &= encoder.set_total_samples_estimate(total_samples);
+
+	/* now add some metadata; we'll add some tags and a padding block */
+	if(ok) {
+		if(
+			(metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL ||
+			(metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL ||
+			/* there are many tag (vorbiscomment) functions but these are convenient for this particular use: */
+			!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", "Some Artist") ||
+			!FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false) || /* copy=false: let metadata object take control of entry's allocated string */
+			!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "YEAR", "1984") ||
+			!FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false)
+		) {
+			fprintf(stderr, "ERROR: out of memory or tag error\n");
+			ok = false;
+		}
+
+		metadata[1]->length = 1234; /* set the padding length */
+
+		ok = encoder.set_metadata(metadata, 2);
+	}
+
+	/* initialize encoder */
+	if(ok) {
+		init_status = encoder.init(argv[2]);
+		if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+			fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
+			ok = false;
+		}
+	}
+
+	/* read blocks of samples from WAVE file and feed to encoder */
+	if(ok) {
+		size_t left = (size_t)total_samples;
+		while(ok && left) {
+			size_t need = (left>READSIZE? (size_t)READSIZE : (size_t)left);
+			if(fread(buffer, channels*(bps/8), need, fin) != need) {
+				fprintf(stderr, "ERROR: reading from WAVE file\n");
+				ok = false;
+			}
+			else {
+				/* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
+				size_t i;
+				for(i = 0; i < need*channels; i++) {
+					/* inefficient but simple and works on big- or little-endian machines */
+					pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
+				}
+				/* feed samples to encoder */
+				ok = encoder.process_interleaved(pcm, need);
+			}
+			left -= need;
+		}
+	}
+
+	ok &= encoder.finish();
+
+	fprintf(stderr, "encoding: %s\n", ok? "succeeded" : "FAILED");
+	fprintf(stderr, "   state: %s\n", encoder.get_state().resolved_as_cstring(encoder));
+
+	/* now that encoding is finished, the metadata can be freed */
+	FLAC__metadata_object_delete(metadata[0]);
+	FLAC__metadata_object_delete(metadata[1]);
+
+	fclose(fin);
+
+	return 0;
+}
+
+void OurEncoder::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate)
+{
+	fprintf(stderr, "wrote %" PRIu64 " bytes, %" PRIu64 "/%u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
+}
diff --git a/flac-config.cmake.in b/flac-config.cmake.in
new file mode 100644
index 0000000..f44133c
--- /dev/null
+++ b/flac-config.cmake.in
@@ -0,0 +1,15 @@
+@PACKAGE_INIT@
+
+include(CMakeFindDependencyMacro)
+find_dependency(Ogg)
+
+include("${CMAKE_CURRENT_LIST_DIR}/targets.cmake")
+
+if(TARGET FLAC::FLAC)
+    set(FLAC_FLAC_FOUND 1)
+endif()
+if(TARGET FLAC::FLAC++)
+    set(FLAC_FLAC++_FOUND 1)
+endif()
+
+check_required_components(FLAC)
diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp
new file mode 100644
index 0000000..d813920
--- /dev/null
+++ b/fuzzer/Android.bp
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "external_flac_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["external_flac_license"],
+}
+
+cc_fuzz {
+    name: "flac_dec_fuzzer",
+    host_supported: true,
+
+    static_libs: [
+        "libFLAC",
+    ],
+
+    srcs: [
+        "flac_dec_fuzzer.cpp",
+    ],
+
+    fuzz_config: {
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 155276,
+    },
+}
+
+cc_fuzz {
+    name: "flac_enc_fuzzer",
+    host_supported: true,
+
+    header_libs: [
+        "libaudioutils_headers",
+    ],
+
+    static_libs: [
+        "libFLAC",
+        "libaudioutils",
+    ],
+
+    srcs: [
+        "flac_enc_fuzzer.cpp",
+    ],
+
+    fuzz_config: {
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 155276,
+    },
+}
diff --git a/fuzzer/README.md b/fuzzer/README.md
new file mode 100644
index 0000000..2d63b18
--- /dev/null
+++ b/fuzzer/README.md
@@ -0,0 +1,119 @@
+# Fuzzer for libFLAC decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for FLAC decoder is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+FLAC supports the following two decoder API's for native mode:
+1. FLAC__stream_decoder_process_single (frame by frame decoding)
+2. FLAC__stream_decoder_process_until_end_of_stream (decoding entire stream)
+
+One of these two decoder API's will be called based on LSB of 5th byte of data.
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the input data to the codec using a read_callback as and when
+requested by the decoder. The read_callback feeds the input data to the decoder
+until the end of stream.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build flac_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) flac_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some flac files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/flac_dec_fuzzer/flac_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/flac_dec_fuzzer/flac_dec_fuzzer CORPUS_DIR
+```
+
+# Fuzzer for libFLAC encoder
+
+## Plugin Design Considerations
+The fuzzer plugin for flac encoder is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+Follwing functions were called in initEncoder to configure the encoder:
+
+| Function name | Parameter| Valid Values| Configured Value|
+|------------- |------------- |-------------| ----- |
+| `FLAC__stream_encoder_set_sample_rate`   | sampleRate |`1 ` to `655350 ` | All the bits of 1st, 2nd and 3rd byte of data |
+| `FLAC__stream_encoder_set_channels`   | mChannels |`1 ` `2 ` | bit 0 of 4th byte of data |
+| `FLAC__stream_encoder_set_compression_level`   | compression |`1 ` `2 ` | bit 0 of 5th byte of data |
+| `FLAC__stream_encoder_set_bits_per_sample`   | bitsPerSample |`16 ` `24 ` | bit 0 of 6th byte of data |
+| `FLAC__stream_encoder_set_verify`   | - |`false ` `true ` |  bit 0 of 7th byte of data |
+| `FLAC__stream_encoder_set_streamable_subset`   | - |`false ` `true ` |  bit 0 of 8th byte of data |
+| `FLAC__stream_encoder_set_do_mid_side_stereo`   | - |`false ` `true ` |  bit 0 of 9th byte of data |
+| `FLAC__stream_encoder_set_loose_mid_side_stereo`   | - |`false ` `true ` |  bit 0 of 10th byte of data |
+| `FLAC__stream_encoder_set_max_lpc_order`   | - |`false ` `true ` |  bit 0 of 11th byte of data|
+| `FLAC__stream_encoder_set_qlp_coeff_precision`   | - |`0 ` `1 ` |  bit 0 of 12th byte of data |
+| `FLAC__stream_encoder_set_do_qlp_coeff_prec_search`   | - |`false ` `true ` |  bit 0 of 13th byte of data |
+| `FLAC__stream_encoder_set_do_escape_coding`   | - |`false ` `true ` |  bit 0 of 14th byte of data|
+| `FLAC__stream_encoder_set_do_exhaustive_model_search`   | - |`false ` `true ` |  bit 0 of 15th byte of data |
+| `FLAC__stream_encoder_set_min_residual_partition_order`   | - |`0 ` `1 ` |  bit 0 of 16th byte of data |
+| `FLAC__stream_encoder_set_max_residual_partition_order`   | - |`0 ` `1 ` |  bit 0 of 17th byte of data |
+| `FLAC__stream_encoder_set_rice_parameter_search_dist`   | - |`0 ` `1 ` |  bit 0 of 18th byte of data|
+| `FLAC__stream_encoder_set_total_samples_estimate`   | - |`0 ` `1 ` |  bit 0 of 19th byte of data|
+
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec and continues with the encoding even on a failure. This ensures that the plugin tolerates any kind of input (empty, huge, malformed, etc) and doesn't `exit()` on any input and thereby increasing the chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build flac_enc_fuzzer binary.
+
+## Android
+
+### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) flac_enc_fuzzer
+```
+
+### Steps to run
+Create a directory CORPUS_DIR and copy some wav files to that folder.
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/flac_enc_fuzzer/flac_enc_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/flac_enc_fuzzer/flac_enc_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/fuzzer/flac_dec_fuzzer.cpp b/fuzzer/flac_dec_fuzzer.cpp
new file mode 100644
index 0000000..61413c4
--- /dev/null
+++ b/fuzzer/flac_dec_fuzzer.cpp
@@ -0,0 +1,162 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+#include <stdlib.h>
+#include <utils/String8.h>
+#include "FLAC/stream_decoder.h"
+
+// First four bytes are always "fLaC" in ASCII format.
+#define FIRST_ENCODED_BYTE_OFFSET 4
+
+class Codec {
+ public:
+  Codec() = default;
+  ~Codec() { deInitDecoder(); }
+  bool initDecoder();
+  void decodeFrames(const uint8_t *data, size_t size);
+  void deInitDecoder();
+
+ private:
+  FLAC__StreamDecoder *mDecoder = nullptr;
+  const uint8_t *mBuffer = nullptr;
+  size_t mBufferLen = 0;
+  size_t mBufferPos = 0;
+  FLAC__StreamDecoderReadStatus readCallback(FLAC__byte buffer[], size_t *bytes);
+  FLAC__StreamDecoderWriteStatus writeCallback(const FLAC__Frame *frame,
+                                               const FLAC__int32 *const buffer[]);
+  void errorCallback(FLAC__StreamDecoderErrorStatus status);
+  void metadataCallback(const FLAC__StreamMetadata *metadata);
+};
+
+bool Codec::initDecoder() {
+  mDecoder = FLAC__stream_decoder_new();
+  if (!mDecoder) {
+    return false;
+  }
+  FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
+  FLAC__stream_decoder_set_md5_checking(mDecoder, true);
+  // read_callback, write_callback, error_callback and metadata_callback cannot be nullptrs
+
+  static auto read_callback = [](const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes,
+                                 void *client_data) -> FLAC__StreamDecoderReadStatus {
+    Codec *client = reinterpret_cast<Codec *>(client_data);
+    return client->readCallback(buffer, bytes);
+  };
+  static auto write_callback = [](const FLAC__StreamDecoder *, const FLAC__Frame *frame,
+                                  const FLAC__int32 *const buffer[],
+                                  void *client_data) -> FLAC__StreamDecoderWriteStatus {
+    Codec *client = reinterpret_cast<Codec *>(client_data);
+    return client->writeCallback(frame, buffer);
+  };
+  static auto error_callback = [](const FLAC__StreamDecoder *,
+                                  FLAC__StreamDecoderErrorStatus status, void *client_data) {
+    Codec *client = reinterpret_cast<Codec *>(client_data);
+    client->errorCallback(status);
+  };
+  FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_STREAMINFO);
+  static auto metadata_callback = [](const FLAC__StreamDecoder *,
+                                     const FLAC__StreamMetadata *metadata, void *client_data) {
+    Codec *client = reinterpret_cast<Codec *>(client_data);
+    client->metadataCallback(metadata);
+  };
+  void *client_data = reinterpret_cast<void *>(this);
+  FLAC__StreamDecoderInitStatus initStatus = FLAC__stream_decoder_init_stream(
+      mDecoder, read_callback, nullptr, nullptr, nullptr, nullptr, write_callback,
+      metadata_callback, error_callback, client_data);
+  if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+    return false;
+  }
+  return true;
+}
+
+FLAC__StreamDecoderReadStatus Codec::readCallback(FLAC__byte buffer[], size_t *bytes) {
+  if (!mBuffer || mBufferLen == 0) {
+    *bytes = 0;
+    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+  }
+  size_t bytesRequested = *bytes;
+  if (bytesRequested > mBufferLen - mBufferPos) {
+    bytesRequested = mBufferLen - mBufferPos;
+  }
+  memcpy(buffer, mBuffer + mBufferPos, bytesRequested);
+  mBufferPos += bytesRequested;
+  *bytes = bytesRequested;
+  return (bytesRequested == 0 ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
+                              : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE);
+}
+
+FLAC__StreamDecoderWriteStatus Codec::writeCallback(const FLAC__Frame *frame,
+                                                    const FLAC__int32 *const buffer[]) {
+  (void)frame;
+  (void)buffer;
+  return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void Codec::errorCallback(FLAC__StreamDecoderErrorStatus status) {
+  (void)status;
+  return;
+}
+
+void Codec::metadataCallback(const FLAC__StreamMetadata *metadata) {
+  (void)metadata;
+  return;
+}
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+  mBuffer = data;
+  mBufferLen = size;
+  size_t ofst = std::min((size_t)FIRST_ENCODED_BYTE_OFFSET, size - 1);
+  bool decodeEntireStream = data[ofst] & 0x01;
+  if (!decodeEntireStream) {
+    if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
+      return;
+    }
+    while (mBufferPos <= size) {
+      FLAC__stream_decoder_process_single(mDecoder);
+      if (FLAC__STREAM_DECODER_END_OF_STREAM == FLAC__stream_decoder_get_state(mDecoder)) {
+        return;
+      }
+    }
+  } else {
+    FLAC__stream_decoder_process_until_end_of_stream(mDecoder);
+  }
+  FLAC__stream_decoder_finish(mDecoder);
+}
+
+void Codec::deInitDecoder() {
+  if (mDecoder != nullptr) {
+    FLAC__stream_decoder_delete(mDecoder);
+  }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size == 0) {
+    return 0;
+  }
+  Codec *codec = new Codec();
+  if (!codec) {
+    return 0;
+  }
+  if (codec->initDecoder()) {
+    codec->decodeFrames(data, size);
+  }
+  delete codec;
+  return 0;
+}
diff --git a/fuzzer/flac_dec_fuzzer.dict b/fuzzer/flac_dec_fuzzer.dict
new file mode 100644
index 0000000..53ad44f
--- /dev/null
+++ b/fuzzer/flac_dec_fuzzer.dict
@@ -0,0 +1,3 @@
+# Start code (bytes 0-3)
+# The below 4 bytes correspond to "fLaC" in ASCII
+kw1="\x66\x4C\x61\x43"
diff --git a/fuzzer/flac_enc_fuzzer.cpp b/fuzzer/flac_enc_fuzzer.cpp
new file mode 100644
index 0000000..3cbc64d
--- /dev/null
+++ b/fuzzer/flac_enc_fuzzer.cpp
@@ -0,0 +1,228 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <algorithm>
+
+#include "FLAC/stream_encoder.h"
+#include "audio_utils/primitives.h"
+#include "share/compat.h"
+
+constexpr int kMinSampleRate = 1;
+constexpr int kFramesPerBlock = 1152;
+constexpr int kMaxSampleRate = 655350;
+constexpr uint8_t kMinNumChannels = 1;
+constexpr uint8_t kMaxNumChannels = 2;
+constexpr uint8_t kMinCompressionLevel = 0;
+constexpr uint8_t kMaxCompressionLevel = 8;
+
+enum Encoding { PCM_16, PCM_FLOAT };
+
+enum {
+    IDX_SAMPLE_RATE_INDEX_1 = 0,
+    IDX_SAMPLE_RATE_INDEX_2,
+    IDX_SAMPLE_RATE_INDEX_3,
+    IDX_CHANNEL,
+    IDX_COMPRESSION_LEVEL,
+    IDX_PCM,
+    IDX_SET_VERIFY,
+    IDX_SET_STREAMABLE_SUBSET,
+    IDX_SET_DO_MID_SIDE_STEREO,
+    IDX_SET_LOOSE_MID_SIDE_STEREO,
+    IDX_SET_MAX_LPC_ORDER,
+    IDX_SET_COEFF_PRECISION,
+    IDX_SET_COEFF_PREC_SEARCH,
+    IDX_SET_DO_ESCAPE_CODING,
+    IDX_SET_DO_EXHAUSTIVE_MODEL_SEARCH,
+    IDX_SET_MIN_RESIDUAL_PARTITION_ORDER,
+    IDX_SET_MAX_RESIDUAL_PARTITION_ORDER,
+    IDX_SET_RICE_PARAMETER_SEARCH_DIST,
+    IDX_SET_TOTAL_SAMPLES_ESTIMATE,
+    IDX_LAST
+};
+
+class Codec {
+   public:
+    ~Codec() { deInitEncoder(); }
+    bool initEncoder(uint8_t **dataPtr, size_t *sizePtr);
+    void encodeFrames(const uint8_t *data, size_t size);
+    void deInitEncoder();
+    static FLAC__StreamEncoderWriteStatus flacEncoderWriteCallback(
+        const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes,
+        unsigned samples, unsigned current_frame, void *client_data);
+
+   private:
+    bool verifyStateAndReturn();
+    FLAC__StreamEncoder *mFlacStreamEncoder = nullptr;
+    uint32_t mChannels = 0;
+    uint32_t mPcmEncodingInfo = 0;
+    FLAC__int32 mInputBufferPcm32[kFramesPerBlock * kMaxNumChannels] = {};
+};
+
+FLAC__StreamEncoderWriteStatus Codec::flacEncoderWriteCallback(const FLAC__StreamEncoder *encoder,
+                                                               const FLAC__byte buffer[],
+                                                               size_t bytes, unsigned samples,
+                                                               unsigned current_frame,
+                                                               void *client_data) {
+    (void)encoder;
+    (void)buffer;
+    (void)bytes;
+    (void)samples;
+    (void)current_frame;
+    (void)client_data;
+    return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+bool Codec::verifyStateAndReturn() {
+    FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(mFlacStreamEncoder);
+    if (state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+        FLAC__stream_encoder_get_verify_decoder_state(mFlacStreamEncoder);
+    }
+    return false;
+}
+
+template <typename type1, typename type2, typename type3>
+auto generateNumberInRangeFromData(type1 data, type2 min, type3 max) -> decltype(max) {
+    return (data % (1 + max - min)) + min;
+}
+
+bool Codec::initEncoder(uint8_t **dataPtr, size_t *sizePtr) {
+    uint8_t *data = *dataPtr;
+    mFlacStreamEncoder = FLAC__stream_encoder_new();
+    if (!mFlacStreamEncoder) {
+        return false;
+    }
+
+    // Clubbing 3 bytes of data to ensure sample rate in the range [1, 655350]
+    uint32_t tempValue = (data[IDX_SAMPLE_RATE_INDEX_1] << 16) |
+                         (data[IDX_SAMPLE_RATE_INDEX_2] << 8) | data[IDX_SAMPLE_RATE_INDEX_3];
+    uint32_t sampleRate = generateNumberInRangeFromData(tempValue, kMinSampleRate, kMaxSampleRate);
+    FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, sampleRate);
+
+    mChannels = generateNumberInRangeFromData(data[IDX_CHANNEL], kMinNumChannels, kMaxNumChannels);
+    FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mChannels);
+
+    int compression = generateNumberInRangeFromData(data[IDX_COMPRESSION_LEVEL],
+                                                    kMinCompressionLevel, kMaxCompressionLevel);
+    FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder, compression);
+
+    uint32_t pcmEncodingInfo =
+        generateNumberInRangeFromData(data[IDX_PCM], (int)PCM_16, (int)PCM_FLOAT);
+    mPcmEncodingInfo = pcmEncodingInfo;
+    uint32_t bitsPerSample = (mPcmEncodingInfo == PCM_FLOAT) ? 24 : 16;
+    FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, bitsPerSample);
+
+    int ver = data[IDX_SET_VERIFY] % 2;
+    FLAC__stream_encoder_set_verify(mFlacStreamEncoder, ver);
+
+    int streamableSubset = data[IDX_SET_STREAMABLE_SUBSET] % 2;
+    FLAC__stream_encoder_set_streamable_subset(mFlacStreamEncoder, streamableSubset);
+
+    int doMidSideStereo = data[IDX_SET_DO_MID_SIDE_STEREO] % 2;
+    FLAC__stream_encoder_set_do_mid_side_stereo(mFlacStreamEncoder, doMidSideStereo);
+
+    int looseMidSideStereo = data[IDX_SET_LOOSE_MID_SIDE_STEREO] % 2;
+    FLAC__stream_encoder_set_loose_mid_side_stereo(mFlacStreamEncoder, looseMidSideStereo);
+
+    int maxLpcOrder = data[IDX_SET_MAX_LPC_ORDER] % 2;
+    FLAC__stream_encoder_set_max_lpc_order(mFlacStreamEncoder, maxLpcOrder);
+
+    int coeffPrec = data[IDX_SET_COEFF_PRECISION] % 2;
+    FLAC__stream_encoder_set_qlp_coeff_precision(mFlacStreamEncoder, coeffPrec);
+
+    int coeffPrecSearch = data[IDX_SET_COEFF_PREC_SEARCH] % 2;
+    FLAC__stream_encoder_set_do_qlp_coeff_prec_search(mFlacStreamEncoder, coeffPrecSearch);
+
+    int escCoding = data[IDX_SET_DO_ESCAPE_CODING] % 2;
+    FLAC__stream_encoder_set_do_escape_coding(mFlacStreamEncoder, escCoding);
+
+    int exhaustiveModelSearch = data[IDX_SET_DO_EXHAUSTIVE_MODEL_SEARCH] % 2;
+    FLAC__stream_encoder_set_do_exhaustive_model_search(mFlacStreamEncoder, exhaustiveModelSearch);
+
+    int minResidualPartitionOrder = data[IDX_SET_MIN_RESIDUAL_PARTITION_ORDER] % 2;
+    FLAC__stream_encoder_set_min_residual_partition_order(mFlacStreamEncoder,
+                                                          minResidualPartitionOrder);
+
+    int maxResidualPartitionOrder = data[IDX_SET_MAX_RESIDUAL_PARTITION_ORDER] % 2;
+    FLAC__stream_encoder_set_max_residual_partition_order(mFlacStreamEncoder,
+                                                          maxResidualPartitionOrder);
+
+    int riceParam = data[IDX_SET_RICE_PARAMETER_SEARCH_DIST] % 2;
+    FLAC__stream_encoder_set_rice_parameter_search_dist(mFlacStreamEncoder, riceParam);
+
+    int totalSamplesEstimate = data[IDX_SET_TOTAL_SAMPLES_ESTIMATE] % 2;
+    FLAC__stream_encoder_set_total_samples_estimate(mFlacStreamEncoder, totalSamplesEstimate);
+
+    FLAC__StreamEncoderInitStatus status = FLAC__stream_encoder_init_stream(
+        mFlacStreamEncoder, flacEncoderWriteCallback /*write_callback*/, nullptr /*seek_callback*/,
+        nullptr /*tell_callback*/, nullptr /*metadata_callback*/, (void *)this /*client_data*/);
+
+    if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+        return verifyStateAndReturn();
+    }
+
+    // Not re-using the data which was used for configuration for encoding
+    *dataPtr += IDX_LAST;
+    *sizePtr -= IDX_LAST;
+    return true;
+}
+
+void Codec::encodeFrames(const uint8_t *data, size_t size) {
+    size_t sampleSize = (mPcmEncodingInfo == PCM_FLOAT) ? sizeof(float) : sizeof(int16_t);
+    size_t frameSize = mChannels * sampleSize;
+    do {
+        const size_t bytesConsumed = std::min(kFramesPerBlock * frameSize, size);
+        const unsigned inputFrames = bytesConsumed / frameSize;
+        const unsigned inputSamples = inputFrames * mChannels;
+        if (mPcmEncodingInfo == PCM_FLOAT) {
+            const float *const pcmFloat = reinterpret_cast<const float *>(data);
+            memcpy_to_q8_23_from_float_with_clamp(mInputBufferPcm32, pcmFloat, inputSamples);
+        } else {
+            const int16_t *const pcm16 = reinterpret_cast<const int16_t *>(data);
+            for (unsigned i = 0; i < inputSamples; ++i) {
+                mInputBufferPcm32[i] = (FLAC__int32)pcm16[i];
+            }
+        }
+        FLAC__stream_encoder_process_interleaved(mFlacStreamEncoder, mInputBufferPcm32,
+                                                 inputFrames);
+        data += bytesConsumed;
+        size -= bytesConsumed;
+    } while (size > 0);
+}
+
+void Codec::deInitEncoder() {
+    if (mFlacStreamEncoder) {
+        FLAC__stream_encoder_finish(mFlacStreamEncoder);
+        FLAC__stream_encoder_delete(mFlacStreamEncoder);
+        mFlacStreamEncoder = nullptr;
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    if (size < IDX_LAST) {
+        return 0;
+    }
+    Codec encoder;
+    if (encoder.initEncoder(const_cast<uint8_t **>(&data), &size)) {
+        encoder.encodeFrames(data, size);
+    }
+    return 0;
+}
diff --git a/include/FLAC++/Makefile.am b/include/FLAC++/Makefile.am
new file mode 100644
index 0000000..118361e
--- /dev/null
+++ b/include/FLAC++/Makefile.am
@@ -0,0 +1,39 @@
+#  libFLAC++ - Free Lossless Audio Codec library
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+flaccppincludedir = $(includedir)/FLAC++
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+flaccppinclude_HEADERS = \
+	all.h \
+	decoder.h \
+	encoder.h \
+	export.h \
+	metadata.h
diff --git a/include/FLAC++/all.h b/include/FLAC++/all.h
new file mode 100644
index 0000000..b679d0f
--- /dev/null
+++ b/include/FLAC++/all.h
@@ -0,0 +1,49 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 FLACPP__ALL_H
+#define FLACPP__ALL_H
+
+#include "export.h"
+
+#include "encoder.h"
+#include "decoder.h"
+#include "metadata.h"
+
+/** \defgroup flacpp FLAC C++ API
+ *
+ * The FLAC C++ API is the interface to libFLAC++, a set of classes
+ * that encapsulate the encoders, decoders, and metadata interfaces
+ * in libFLAC.
+ */
+
+#endif
diff --git a/include/FLAC++/decoder.h b/include/FLAC++/decoder.h
new file mode 100644
index 0000000..6a2d901
--- /dev/null
+++ b/include/FLAC++/decoder.h
@@ -0,0 +1,248 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 FLACPP__DECODER_H
+#define FLACPP__DECODER_H
+
+#include "export.h"
+
+#include <string>
+#include "FLAC/stream_decoder.h"
+
+
+/** \file include/FLAC++/decoder.h
+ *
+ *  \brief
+ *  This module contains the classes which implement the various
+ *  decoders.
+ *
+ *  See the detailed documentation in the
+ *  \link flacpp_decoder decoder \endlink module.
+ */
+
+/** \defgroup flacpp_decoder FLAC++/decoder.h: decoder classes
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  This module describes the decoder layers provided by libFLAC++.
+ *
+ * The libFLAC++ decoder classes are object wrappers around their
+ * counterparts in libFLAC.  All decoding layers available in
+ * libFLAC are also provided here.  The interface is very similar;
+ * make sure to read the \link flac_decoder libFLAC decoder module \endlink.
+ *
+ * There are only two significant differences here.  First, instead of
+ * passing in C function pointers for callbacks, you inherit from the
+ * decoder class and provide implementations for the callbacks in your
+ * derived class; because of this there is no need for a 'client_data'
+ * property.
+ *
+ * Second, there are two stream decoder classes.  FLAC::Decoder::Stream
+ * is used for the same cases that FLAC__stream_decoder_init_stream() /
+ * FLAC__stream_decoder_init_ogg_stream() are used, and FLAC::Decoder::File
+ * is used for the same cases that
+ * FLAC__stream_decoder_init_FILE() and FLAC__stream_decoder_init_file() /
+ * FLAC__stream_decoder_init_ogg_FILE() and FLAC__stream_decoder_init_ogg_file()
+ * are used.
+ */
+
+namespace FLAC {
+	namespace Decoder {
+
+		/** \ingroup flacpp_decoder
+		 *  \brief
+		 *  This class wraps the ::FLAC__StreamDecoder.  If you are
+		 *  decoding from a file, FLAC::Decoder::File may be more
+		 *  convenient.
+		 *
+		 * The usage of this class is similar to FLAC__StreamDecoder,
+		 * except instead of providing callbacks to
+		 * FLAC__stream_decoder_init*_stream(), you will inherit from this
+		 * class and override the virtual callback functions with your
+		 * own implementations, then call init() or init_ogg().  The rest
+		 * of the calls work the same as in the C layer.
+		 *
+		 * Only the read, write, and error callbacks are mandatory.  The
+		 * others are optional; this class provides default
+		 * implementations that do nothing.  In order for seeking to work
+		 * you must override seek_callback(), tell_callback(),
+		 * length_callback(), and eof_callback().
+		 */
+		class FLACPP_API Stream {
+		public:
+			/** This class is a wrapper around FLAC__StreamDecoderState.
+			 */
+			class FLACPP_API State {
+			public:
+				inline State(::FLAC__StreamDecoderState state): state_(state) { }
+				inline operator ::FLAC__StreamDecoderState() const { return state_; }
+				inline const char *as_cstring() const { return ::FLAC__StreamDecoderStateString[state_]; }
+				inline const char *resolved_as_cstring(const Stream &decoder) const { return ::FLAC__stream_decoder_get_resolved_state_string(decoder.decoder_); }
+			protected:
+				::FLAC__StreamDecoderState state_;
+			};
+
+			Stream();
+			virtual ~Stream();
+
+			//@{
+			/** Call after construction to check that the object was created
+			 *  successfully.  If not, use get_state() to find out why not.
+			 */
+			virtual bool is_valid() const;
+			inline operator bool() const { return is_valid(); } ///< See is_valid()
+			//@}
+
+			virtual bool set_ogg_serial_number(long value);                        ///< See FLAC__stream_decoder_set_ogg_serial_number()
+			virtual bool set_md5_checking(bool value);                             ///< See FLAC__stream_decoder_set_md5_checking()
+			virtual bool set_metadata_respond(::FLAC__MetadataType type);          ///< See FLAC__stream_decoder_set_metadata_respond()
+			virtual bool set_metadata_respond_application(const FLAC__byte id[4]); ///< See FLAC__stream_decoder_set_metadata_respond_application()
+			virtual bool set_metadata_respond_all();                               ///< See FLAC__stream_decoder_set_metadata_respond_all()
+			virtual bool set_metadata_ignore(::FLAC__MetadataType type);           ///< See FLAC__stream_decoder_set_metadata_ignore()
+			virtual bool set_metadata_ignore_application(const FLAC__byte id[4]);  ///< See FLAC__stream_decoder_set_metadata_ignore_application()
+			virtual bool set_metadata_ignore_all();                                ///< See FLAC__stream_decoder_set_metadata_ignore_all()
+
+			/* get_state() is not virtual since we want subclasses to be able to return their own state */
+			State get_state() const;                                          ///< See FLAC__stream_decoder_get_state()
+			virtual bool get_md5_checking() const;                            ///< See FLAC__stream_decoder_get_md5_checking()
+			virtual FLAC__uint64 get_total_samples() const;                   ///< See FLAC__stream_decoder_get_total_samples()
+			virtual uint32_t get_channels() const;                            ///< See FLAC__stream_decoder_get_channels()
+			virtual ::FLAC__ChannelAssignment get_channel_assignment() const; ///< See FLAC__stream_decoder_get_channel_assignment()
+			virtual uint32_t get_bits_per_sample() const;                     ///< See FLAC__stream_decoder_get_bits_per_sample()
+			virtual uint32_t get_sample_rate() const;                         ///< See FLAC__stream_decoder_get_sample_rate()
+			virtual uint32_t get_blocksize() const;                           ///< See FLAC__stream_decoder_get_blocksize()
+			virtual bool get_decode_position(FLAC__uint64 *position) const;   ///< See FLAC__stream_decoder_get_decode_position()
+
+			virtual ::FLAC__StreamDecoderInitStatus init();      ///< Seek FLAC__stream_decoder_init_stream()
+			virtual ::FLAC__StreamDecoderInitStatus init_ogg();  ///< Seek FLAC__stream_decoder_init_ogg_stream()
+
+			virtual bool finish(); ///< See FLAC__stream_decoder_finish()
+
+			virtual bool flush(); ///< See FLAC__stream_decoder_flush()
+			virtual bool reset(); ///< See FLAC__stream_decoder_reset()
+
+			virtual bool process_single();                ///< See FLAC__stream_decoder_process_single()
+			virtual bool process_until_end_of_metadata(); ///< See FLAC__stream_decoder_process_until_end_of_metadata()
+			virtual bool process_until_end_of_stream();   ///< See FLAC__stream_decoder_process_until_end_of_stream()
+			virtual bool skip_single_frame();             ///< See FLAC__stream_decoder_skip_single_frame()
+
+			virtual bool seek_absolute(FLAC__uint64 sample); ///< See FLAC__stream_decoder_seek_absolute()
+		protected:
+			/// see FLAC__StreamDecoderReadCallback
+			virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) = 0;
+
+			/// see FLAC__StreamDecoderSeekCallback
+			virtual ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+
+			/// see FLAC__StreamDecoderTellCallback
+			virtual ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+
+			/// see FLAC__StreamDecoderLengthCallback
+			virtual ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length);
+
+			/// see FLAC__StreamDecoderEofCallback
+			virtual bool eof_callback();
+
+			/// see FLAC__StreamDecoderWriteCallback
+			virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) = 0;
+
+			/// see FLAC__StreamDecoderMetadataCallback
+			virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+
+			/// see FLAC__StreamDecoderErrorCallback
+			virtual void error_callback(::FLAC__StreamDecoderErrorStatus status) = 0;
+
+#if (defined __BORLANDC__) || (defined __GNUG__ && (__GNUG__ < 2 || (__GNUG__ == 2 && __GNUC_MINOR__ < 96))) || (defined __SUNPRO_CC)
+			// lame hack: some compilers can't see a protected decoder_ from nested State::resolved_as_cstring()
+			friend State;
+#endif
+			::FLAC__StreamDecoder *decoder_;
+
+			static ::FLAC__StreamDecoderReadStatus read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+			static ::FLAC__StreamDecoderSeekStatus seek_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+			static ::FLAC__StreamDecoderTellStatus tell_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+			static ::FLAC__StreamDecoderLengthStatus length_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+			static FLAC__bool eof_callback_(const ::FLAC__StreamDecoder *decoder, 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);
+		private:
+			// Private and undefined so you can't use them:
+			Stream(const Stream &);
+			void operator=(const Stream &);
+		};
+
+		/** \ingroup flacpp_decoder
+		 *  \brief
+		 *  This class wraps the ::FLAC__StreamDecoder.  If you are
+		 *  not decoding from a file, you may need to use
+		 *  FLAC::Decoder::Stream.
+		 *
+		 * The usage of this class is similar to FLAC__StreamDecoder,
+		 * except instead of providing callbacks to
+		 * FLAC__stream_decoder_init*_FILE() or
+		 * FLAC__stream_decoder_init*_file(), you will inherit from this
+		 * class and override the virtual callback functions with your
+		 * own implementations, then call init() or init_off().  The rest
+		 * of the calls work the same as in the C layer.
+		 *
+		 * Only the write, and error callbacks from FLAC::Decoder::Stream
+		 * are mandatory.  The others are optional; this class provides
+		 * full working implementations for all other callbacks and
+		 * supports seeking.
+		 */
+		class FLACPP_API File: public Stream {
+		public:
+			File();
+			virtual ~File();
+
+			using Stream::init;
+			virtual ::FLAC__StreamDecoderInitStatus init(FILE *file);                      ///< See FLAC__stream_decoder_init_FILE()
+			virtual ::FLAC__StreamDecoderInitStatus init(const char *filename);            ///< See FLAC__stream_decoder_init_file()
+			virtual ::FLAC__StreamDecoderInitStatus init(const std::string &filename);     ///< See FLAC__stream_decoder_init_file()
+			using Stream::init_ogg;
+			virtual ::FLAC__StreamDecoderInitStatus init_ogg(FILE *file);                  ///< See FLAC__stream_decoder_init_ogg_FILE()
+			virtual ::FLAC__StreamDecoderInitStatus init_ogg(const char *filename);        ///< See FLAC__stream_decoder_init_ogg_file()
+			virtual ::FLAC__StreamDecoderInitStatus init_ogg(const std::string &filename); ///< See FLAC__stream_decoder_init_ogg_file()
+		protected:
+			// this is a dummy implementation to satisfy the pure virtual in Stream that is actually supplied internally by the C layer
+			virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
+		private:
+			// Private and undefined so you can't use them:
+			File(const File &);
+			void operator=(const File &);
+		};
+
+	}
+}
+
+#endif
diff --git a/include/FLAC++/encoder.h b/include/FLAC++/encoder.h
new file mode 100644
index 0000000..ce8d80a
--- /dev/null
+++ b/include/FLAC++/encoder.h
@@ -0,0 +1,263 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 FLACPP__ENCODER_H
+#define FLACPP__ENCODER_H
+
+#include "export.h"
+
+#include "FLAC/stream_encoder.h"
+#include "decoder.h"
+#include "metadata.h"
+
+
+/** \file include/FLAC++/encoder.h
+ *
+ *  \brief
+ *  This module contains the classes which implement the various
+ *  encoders.
+ *
+ *  See the detailed documentation in the
+ *  \link flacpp_encoder encoder \endlink module.
+ */
+
+/** \defgroup flacpp_encoder FLAC++/encoder.h: encoder classes
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  This module describes the encoder layers provided by libFLAC++.
+ *
+ * The libFLAC++ encoder classes are object wrappers around their
+ * counterparts in libFLAC.  All encoding layers available in
+ * libFLAC are also provided here.  The interface is very similar;
+ * make sure to read the \link flac_encoder libFLAC encoder module \endlink.
+ *
+ * There are only two significant differences here.  First, instead of
+ * passing in C function pointers for callbacks, you inherit from the
+ * encoder class and provide implementations for the callbacks in your
+ * derived class; because of this there is no need for a 'client_data'
+ * property.
+ *
+ * Second, there are two stream encoder classes.  FLAC::Encoder::Stream
+ * is used for the same cases that FLAC__stream_encoder_init_stream() /
+ * FLAC__stream_encoder_init_ogg_stream() are used, and FLAC::Encoder::File
+ * is used for the same cases that
+ * FLAC__stream_encoder_init_FILE() and FLAC__stream_encoder_init_file() /
+ * FLAC__stream_encoder_init_ogg_FILE() and FLAC__stream_encoder_init_ogg_file()
+ * are used.
+ */
+
+namespace FLAC {
+	namespace Encoder {
+
+		/** \ingroup flacpp_encoder
+		 *  \brief
+		 *  This class wraps the ::FLAC__StreamEncoder.  If you are
+		 *  encoding to a file, FLAC::Encoder::File may be more
+		 *  convenient.
+		 *
+		 * The usage of this class is similar to FLAC__StreamEncoder,
+		 * except instead of providing callbacks to
+		 * FLAC__stream_encoder_init*_stream(), you will inherit from this
+		 * class and override the virtual callback functions with your
+		 * own implementations, then call init() or init_ogg().  The rest of
+		 * the calls work the same as in the C layer.
+		 *
+		 * Only the write callback is mandatory.  The others are
+		 * optional; this class provides default implementations that do
+		 * nothing.  In order for some STREAMINFO and SEEKTABLE data to
+		 * be written properly, you must override seek_callback() and
+		 * tell_callback(); see FLAC__stream_encoder_init_stream() as to
+		 * why.
+		 */
+		class FLACPP_API Stream {
+		public:
+			/** This class is a wrapper around FLAC__StreamEncoderState.
+			 */
+			class FLACPP_API State {
+			public:
+				inline State(::FLAC__StreamEncoderState state): state_(state) { }
+				inline operator ::FLAC__StreamEncoderState() const { return state_; }
+				inline const char *as_cstring() const { return ::FLAC__StreamEncoderStateString[state_]; }
+				inline const char *resolved_as_cstring(const Stream &encoder) const { return ::FLAC__stream_encoder_get_resolved_state_string(encoder.encoder_); }
+			protected:
+				::FLAC__StreamEncoderState state_;
+			};
+
+			Stream();
+			virtual ~Stream();
+
+			//@{
+			/** Call after construction to check that the object was created
+			 *  successfully.  If not, use get_state() to find out why not.
+			 *
+			 */
+			virtual bool is_valid() const;
+			inline operator bool() const { return is_valid(); } ///< See is_valid()
+			//@}
+
+			virtual bool set_ogg_serial_number(long value);                 ///< See FLAC__stream_encoder_set_ogg_serial_number()
+			virtual bool set_verify(bool value);                            ///< See FLAC__stream_encoder_set_verify()
+			virtual bool set_streamable_subset(bool value);                 ///< See FLAC__stream_encoder_set_streamable_subset()
+			virtual bool set_channels(uint32_t value);                      ///< See FLAC__stream_encoder_set_channels()
+			virtual bool set_bits_per_sample(uint32_t value);               ///< See FLAC__stream_encoder_set_bits_per_sample()
+			virtual bool set_sample_rate(uint32_t value);                   ///< See FLAC__stream_encoder_set_sample_rate()
+			virtual bool set_compression_level(uint32_t value);             ///< See FLAC__stream_encoder_set_compression_level()
+			virtual bool set_blocksize(uint32_t value);                     ///< See FLAC__stream_encoder_set_blocksize()
+			virtual bool set_do_mid_side_stereo(bool value);                ///< See FLAC__stream_encoder_set_do_mid_side_stereo()
+			virtual bool set_loose_mid_side_stereo(bool value);             ///< See FLAC__stream_encoder_set_loose_mid_side_stereo()
+			virtual bool set_apodization(const char *specification);        ///< See FLAC__stream_encoder_set_apodization()
+			virtual bool set_max_lpc_order(uint32_t value);                 ///< See FLAC__stream_encoder_set_max_lpc_order()
+			virtual bool set_qlp_coeff_precision(uint32_t value);           ///< See FLAC__stream_encoder_set_qlp_coeff_precision()
+			virtual bool set_do_qlp_coeff_prec_search(bool value);          ///< See FLAC__stream_encoder_set_do_qlp_coeff_prec_search()
+			virtual bool set_do_escape_coding(bool value);                  ///< See FLAC__stream_encoder_set_do_escape_coding()
+			virtual bool set_do_exhaustive_model_search(bool value);        ///< See FLAC__stream_encoder_set_do_exhaustive_model_search()
+			virtual bool set_min_residual_partition_order(uint32_t value);  ///< See FLAC__stream_encoder_set_min_residual_partition_order()
+			virtual bool set_max_residual_partition_order(uint32_t value);  ///< See FLAC__stream_encoder_set_max_residual_partition_order()
+			virtual bool set_rice_parameter_search_dist(uint32_t value);    ///< See FLAC__stream_encoder_set_rice_parameter_search_dist()
+			virtual bool set_total_samples_estimate(FLAC__uint64 value);    ///< See FLAC__stream_encoder_set_total_samples_estimate()
+			virtual bool set_metadata(::FLAC__StreamMetadata **metadata, uint32_t num_blocks);    ///< See FLAC__stream_encoder_set_metadata()
+			virtual bool set_metadata(FLAC::Metadata::Prototype **metadata, uint32_t num_blocks); ///< See FLAC__stream_encoder_set_metadata()
+
+			/* get_state() is not virtual since we want subclasses to be able to return their own state */
+			State get_state() const;                                   ///< See FLAC__stream_encoder_get_state()
+			virtual Decoder::Stream::State get_verify_decoder_state() const; ///< See FLAC__stream_encoder_get_verify_decoder_state()
+			virtual void get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got); ///< See FLAC__stream_encoder_get_verify_decoder_error_stats()
+			virtual bool     get_verify() const;                       ///< See FLAC__stream_encoder_get_verify()
+			virtual bool     get_streamable_subset() const;            ///< See FLAC__stream_encoder_get_streamable_subset()
+			virtual bool     get_do_mid_side_stereo() const;           ///< See FLAC__stream_encoder_get_do_mid_side_stereo()
+			virtual bool     get_loose_mid_side_stereo() const;        ///< See FLAC__stream_encoder_get_loose_mid_side_stereo()
+			virtual uint32_t get_channels() const;                     ///< See FLAC__stream_encoder_get_channels()
+			virtual uint32_t get_bits_per_sample() const;              ///< See FLAC__stream_encoder_get_bits_per_sample()
+			virtual uint32_t get_sample_rate() const;                  ///< See FLAC__stream_encoder_get_sample_rate()
+			virtual uint32_t get_blocksize() const;                    ///< See FLAC__stream_encoder_get_blocksize()
+			virtual uint32_t get_max_lpc_order() const;                ///< See FLAC__stream_encoder_get_max_lpc_order()
+			virtual uint32_t get_qlp_coeff_precision() const;          ///< See FLAC__stream_encoder_get_qlp_coeff_precision()
+			virtual bool     get_do_qlp_coeff_prec_search() const;     ///< See FLAC__stream_encoder_get_do_qlp_coeff_prec_search()
+			virtual bool     get_do_escape_coding() const;             ///< See FLAC__stream_encoder_get_do_escape_coding()
+			virtual bool     get_do_exhaustive_model_search() const;   ///< See FLAC__stream_encoder_get_do_exhaustive_model_search()
+			virtual uint32_t get_min_residual_partition_order() const; ///< See FLAC__stream_encoder_get_min_residual_partition_order()
+			virtual uint32_t get_max_residual_partition_order() const; ///< See FLAC__stream_encoder_get_max_residual_partition_order()
+			virtual uint32_t get_rice_parameter_search_dist() const;   ///< See FLAC__stream_encoder_get_rice_parameter_search_dist()
+			virtual FLAC__uint64 get_total_samples_estimate() const;   ///< See FLAC__stream_encoder_get_total_samples_estimate()
+
+			virtual ::FLAC__StreamEncoderInitStatus init();            ///< See FLAC__stream_encoder_init_stream()
+			virtual ::FLAC__StreamEncoderInitStatus init_ogg();        ///< See FLAC__stream_encoder_init_ogg_stream()
+
+			virtual bool finish(); ///< See FLAC__stream_encoder_finish()
+
+			virtual bool process(const FLAC__int32 * const buffer[], uint32_t samples);     ///< See FLAC__stream_encoder_process()
+			virtual bool process_interleaved(const FLAC__int32 buffer[], uint32_t samples); ///< See FLAC__stream_encoder_process_interleaved()
+		protected:
+			/// See FLAC__StreamEncoderReadCallback
+			virtual ::FLAC__StreamEncoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
+
+			/// See FLAC__StreamEncoderWriteCallback
+			virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame) = 0;
+
+			/// See FLAC__StreamEncoderSeekCallback
+			virtual ::FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+
+			/// See FLAC__StreamEncoderTellCallback
+			virtual ::FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+
+			/// See FLAC__StreamEncoderMetadataCallback
+			virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+
+#if (defined __BORLANDC__) || (defined __GNUG__ && (__GNUG__ < 2 || (__GNUG__ == 2 && __GNUC_MINOR__ < 96))) || (defined __SUNPRO_CC)
+			// lame hack: some compilers can't see a protected encoder_ from nested State::resolved_as_cstring()
+			friend State;
+#endif
+			::FLAC__StreamEncoder *encoder_;
+
+			static ::FLAC__StreamEncoderReadStatus read_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+			static ::FLAC__StreamEncoderWriteStatus write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data);
+			static ::FLAC__StreamEncoderSeekStatus seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+			static ::FLAC__StreamEncoderTellStatus tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+			static void metadata_callback_(const ::FLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
+		private:
+			// Private and undefined so you can't use them:
+			Stream(const Stream &);
+			void operator=(const Stream &);
+		};
+
+		/** \ingroup flacpp_encoder
+		 *  \brief
+		 *  This class wraps the ::FLAC__StreamEncoder.  If you are
+		 *  not encoding to a file, you may need to use
+		 *  FLAC::Encoder::Stream.
+		 *
+		 * The usage of this class is similar to FLAC__StreamEncoder,
+		 * except instead of providing callbacks to
+		 * FLAC__stream_encoder_init*_FILE() or
+		 * FLAC__stream_encoder_init*_file(), you will inherit from this
+		 * class and override the virtual callback functions with your
+		 * own implementations, then call init() or init_ogg().  The rest
+		 * of the calls work the same as in the C layer.
+		 *
+		 * There are no mandatory callbacks; all the callbacks from
+		 * FLAC::Encoder::Stream are implemented here fully and support
+		 * full post-encode STREAMINFO and SEEKTABLE updating.  There is
+		 * only an optional progress callback which you may override to
+		 * get periodic reports on the progress of the encode.
+		 */
+		class FLACPP_API File: public Stream {
+		public:
+			File();
+			virtual ~File();
+
+			using Stream::init;
+			virtual ::FLAC__StreamEncoderInitStatus init(FILE *file);                      ///< See FLAC__stream_encoder_init_FILE()
+			virtual ::FLAC__StreamEncoderInitStatus init(const char *filename);            ///< See FLAC__stream_encoder_init_file()
+			virtual ::FLAC__StreamEncoderInitStatus init(const std::string &filename);     ///< See FLAC__stream_encoder_init_file()
+			using Stream::init_ogg;
+			virtual ::FLAC__StreamEncoderInitStatus init_ogg(FILE *file);                  ///< See FLAC__stream_encoder_init_ogg_FILE()
+			virtual ::FLAC__StreamEncoderInitStatus init_ogg(const char *filename);        ///< See FLAC__stream_encoder_init_ogg_file()
+			virtual ::FLAC__StreamEncoderInitStatus init_ogg(const std::string &filename); ///< See FLAC__stream_encoder_init_ogg_file()
+		protected:
+			/// See FLAC__StreamEncoderProgressCallback
+			virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate);
+
+			/// This is a dummy implementation to satisfy the pure virtual in Stream that is actually supplied internally by the C layer
+			virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame);
+		private:
+			static void progress_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data);
+
+			// Private and undefined so you can't use them:
+			File(const Stream &);
+			void operator=(const Stream &);
+		};
+
+	}
+}
+
+#endif
diff --git a/include/FLAC++/export.h b/include/FLAC++/export.h
new file mode 100644
index 0000000..d8dccf5
--- /dev/null
+++ b/include/FLAC++/export.h
@@ -0,0 +1,86 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 FLACPP__EXPORT_H
+#define FLACPP__EXPORT_H
+
+/** \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 flacpp_export export \endlink module.
+ */
+
+/** \defgroup flacpp_export FLAC++/export.h: export symbols
+ *  \ingroup flacpp
+ *
+ *  \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 FLACPP_API
+
+#elif defined(_WIN32)
+#ifdef FLACPP_API_EXPORTS
+#define	FLACPP_API __declspec(dllexport)
+#else
+#define FLACPP_API __declspec(dllimport)
+#endif
+
+#elif defined(FLAC__USE_VISIBILITY_ATTR)
+#define FLACPP_API __attribute__ ((visibility ("default")))
+
+#else
+#define FLACPP_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 FLACPP_API_VERSION_CURRENT 9
+#define FLACPP_API_VERSION_REVISION 0
+#define FLACPP_API_VERSION_AGE 3
+
+/* \} */
+
+#endif
diff --git a/include/FLAC++/metadata.h b/include/FLAC++/metadata.h
new file mode 100644
index 0000000..0718e32
--- /dev/null
+++ b/include/FLAC++/metadata.h
@@ -0,0 +1,1234 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 FLACPP__METADATA_H
+#define FLACPP__METADATA_H
+
+#include "export.h"
+
+#include "FLAC/metadata.h"
+
+// ===============================================================
+//
+//  Full documentation for the metadata interface can be found
+//  in the C layer in include/FLAC/metadata.h
+//
+// ===============================================================
+
+/** \file include/FLAC++/metadata.h
+ *
+ *  \brief
+ *  This module provides classes for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  See the detailed documentation for each interface in the
+ *  \link flacpp_metadata metadata \endlink module.
+ */
+
+/** \defgroup flacpp_metadata FLAC++/metadata.h: metadata interfaces
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  This module provides classes for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  The behavior closely mimics the C layer interface; be sure to read
+ *  the detailed description of the
+ *  \link flac_metadata C metadata module \endlink.  Note that like the
+ *  C layer, 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.
+ */
+
+
+namespace FLAC {
+	namespace Metadata {
+
+		// ============================================================
+		//
+		//  Metadata objects
+		//
+		// ============================================================
+
+		/** \defgroup flacpp_metadata_object FLAC++/metadata.h: metadata object classes
+		 *  \ingroup flacpp_metadata
+		 *
+		 * This module contains classes representing FLAC metadata
+		 * blocks in memory.
+		 *
+		 * The behavior closely mimics the C layer interface; be
+		 * sure to read the detailed description of the
+		 * \link flac_metadata_object C metadata object module \endlink.
+		 *
+		 * Any time a metadata object is constructed or assigned, you
+		 * should check is_valid() to make sure the underlying
+		 * ::FLAC__StreamMetadata object was able to be created.
+		 *
+		 * \warning
+		 * When the get_*() methods of any metadata object method
+		 * return you a const pointer, DO NOT disobey and write into it.
+		 * Always use the set_*() methods.
+		 *
+		 * \{
+		 */
+
+		/** Base class for all metadata block types.
+		 *  See the \link flacpp_metadata_object overview \endlink for more.
+		 */
+		class FLACPP_API Prototype {
+		protected:
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			Prototype(const Prototype &);
+			Prototype(const ::FLAC__StreamMetadata &);
+			Prototype(const ::FLAC__StreamMetadata *);
+			//@}
+
+			/** Constructs an object with copy control.  When \a copy
+			 *  is \c true, behaves identically to
+			 *  FLAC::Metadata::Prototype::Prototype(const ::FLAC__StreamMetadata *object).
+			 *  When \a copy is \c false, the instance takes ownership of
+			 *  the pointer and the ::FLAC__StreamMetadata object will
+			 *  be freed by the destructor.
+			 *
+			 *  \assert
+			 *    \code object != NULL \endcode
+			 */
+			Prototype(::FLAC__StreamMetadata *object, bool copy);
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			Prototype &operator=(const Prototype &);
+			Prototype &operator=(const ::FLAC__StreamMetadata &);
+			Prototype &operator=(const ::FLAC__StreamMetadata *);
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			Prototype &assign_object(::FLAC__StreamMetadata *object, bool copy);
+
+			/** Deletes the underlying ::FLAC__StreamMetadata object.
+			 */
+			virtual void clear();
+
+			::FLAC__StreamMetadata *object_;
+		public:
+			/** Deletes the underlying ::FLAC__StreamMetadata object.
+			 */
+			virtual ~Prototype();
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers.
+			 */
+			inline bool operator==(const Prototype &) const;
+			inline bool operator==(const ::FLAC__StreamMetadata &) const;
+			inline bool operator==(const ::FLAC__StreamMetadata *) const;
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const Prototype &) const;
+			inline bool operator!=(const ::FLAC__StreamMetadata &) const;
+			inline bool operator!=(const ::FLAC__StreamMetadata *) const;
+			//@}
+
+			friend class SimpleIterator;
+			friend class Iterator;
+
+			/** Returns \c true if the object was correctly constructed
+			 *  (i.e. the underlying ::FLAC__StreamMetadata object was
+			 *  properly allocated), else \c false.
+			 */
+			inline bool is_valid() const;
+
+			/** Returns \c true if this block is the last block in a
+			 *  stream, else \c false.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
+			bool get_is_last() const;
+
+			/** Returns the type of the block.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
+			::FLAC__MetadataType get_type() const;
+
+			/** Returns the stream length of the metadata block.
+			 *
+			 * \note
+			 *   The length does not include the metadata block header,
+			 *   per spec.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
+			uint32_t get_length() const;
+
+			/** Sets the "is_last" flag for the block.  When using the iterators
+			 *  it is not necessary to set this flag; they will do it for you.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
+			void set_is_last(bool);
+
+			/** Returns a pointer to the underlying ::FLAC__StreamMetadata
+			 *  object.  This can be useful for plugging any holes between
+			 *  the C++ and C interfaces.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
+			inline operator const ::FLAC__StreamMetadata *() const;
+		private:
+			/** Private and undefined so you can't use it. */
+			Prototype();
+
+			// These are used only by Iterator
+			bool is_reference_;
+			inline void set_reference(bool x) { is_reference_ = x; }
+		};
+
+		// local utility routines
+
+		namespace local {
+
+			/** Construct a new object of the type provided in object->type and return it. */
+			Prototype *construct_block(::FLAC__StreamMetadata *object);
+
+		}
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+		inline bool Prototype::operator==(const Prototype &object) const
+		{ return (bool)::FLAC__metadata_object_is_equal(object_, object.object_); }
+
+		inline bool Prototype::operator==(const ::FLAC__StreamMetadata &object) const
+		{ return (bool)::FLAC__metadata_object_is_equal(object_, &object); }
+
+		inline bool Prototype::operator==(const ::FLAC__StreamMetadata *object) const
+		{ return (bool)::FLAC__metadata_object_is_equal(object_, object); }
+
+#ifdef _MSC_VER
+#pragma warning ( default : 4800 )
+#endif
+
+		inline bool Prototype::operator!=(const Prototype &object) const
+		{ return !operator==(object); }
+
+		inline bool Prototype::operator!=(const ::FLAC__StreamMetadata &object) const
+		{ return !operator==(object); }
+
+		inline bool Prototype::operator!=(const ::FLAC__StreamMetadata *object) const
+		{ return !operator==(object); }
+
+		inline bool Prototype::is_valid() const
+		{ return 0 != object_; }
+
+		inline Prototype::operator const ::FLAC__StreamMetadata *() const
+		{ return object_; }
+
+		/** Create a deep copy of an object and return it. */
+		FLACPP_API Prototype *clone(const Prototype *);
+
+
+		/** STREAMINFO metadata block.
+		 *  See the \link flacpp_metadata_object overview \endlink for more,
+		 *  and the <A HREF="../format.html#metadata_block_streaminfo">format specification</A>.
+		 */
+		class FLACPP_API StreamInfo : public Prototype {
+		public:
+			StreamInfo();
+
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline StreamInfo(const StreamInfo &object): Prototype(object) { }
+			inline StreamInfo(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline StreamInfo(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline StreamInfo(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			~StreamInfo();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline StreamInfo &operator=(const StreamInfo &object) { Prototype::operator=(object); return *this; }
+			inline StreamInfo &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline StreamInfo &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline StreamInfo &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const StreamInfo &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const StreamInfo &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			//@{
+			/** See <A HREF="../format.html#metadata_block_streaminfo">format specification</A>. */
+			uint32_t get_min_blocksize() const;
+			uint32_t get_max_blocksize() const;
+			uint32_t get_min_framesize() const;
+			uint32_t get_max_framesize() const;
+			uint32_t get_sample_rate() const;
+			uint32_t get_channels() const;
+			uint32_t get_bits_per_sample() const;
+			FLAC__uint64 get_total_samples() const;
+			const FLAC__byte *get_md5sum() const;
+
+			void set_min_blocksize(uint32_t value);
+			void set_max_blocksize(uint32_t value);
+			void set_min_framesize(uint32_t value);
+			void set_max_framesize(uint32_t value);
+			void set_sample_rate(uint32_t value);
+			void set_channels(uint32_t value);
+			void set_bits_per_sample(uint32_t value);
+			void set_total_samples(FLAC__uint64 value);
+			void set_md5sum(const FLAC__byte value[16]);
+			//@}
+		};
+
+		/** PADDING metadata block.
+		 *  See the \link flacpp_metadata_object overview \endlink for more,
+		 *  and the <A HREF="../format.html#metadata_block_padding">format specification</A>.
+		 */
+		class FLACPP_API Padding : public Prototype {
+		public:
+			Padding();
+
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline Padding(const Padding &object): Prototype(object) { }
+			inline Padding(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline Padding(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Padding(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			/** Constructs an object with the given length.
+			 */
+			Padding(uint32_t length);
+
+			~Padding();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline Padding &operator=(const Padding &object) { Prototype::operator=(object); return *this; }
+			inline Padding &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline Padding &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Padding &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const Padding &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const Padding &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			/** Sets the length in bytes of the padding block.
+			 */
+			void set_length(uint32_t length);
+		};
+
+		/** APPLICATION metadata block.
+		 *  See the \link flacpp_metadata_object overview \endlink for more,
+		 *  and the <A HREF="../format.html#metadata_block_application">format specification</A>.
+		 */
+		class FLACPP_API Application : public Prototype {
+		public:
+			Application();
+			//
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline Application(const Application &object): Prototype(object) { }
+			inline Application(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline Application(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Application(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			~Application();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline Application &operator=(const Application &object) { Prototype::operator=(object); return *this; }
+			inline Application &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline Application &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Application &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const Application &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const Application &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			const FLAC__byte *get_id() const;
+			const FLAC__byte *get_data() const;
+
+			void set_id(const FLAC__byte value[4]);
+			//! This form always copies \a data
+			bool set_data(const FLAC__byte *data, uint32_t length);
+			bool set_data(FLAC__byte *data, uint32_t length, bool copy);
+		};
+
+		/** SEEKTABLE metadata block.
+		 *  See the \link flacpp_metadata_object overview \endlink for more,
+		 *  and the <A HREF="../format.html#metadata_block_seektable">format specification</A>.
+		 */
+		class FLACPP_API SeekTable : public Prototype {
+		public:
+			SeekTable();
+
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline SeekTable(const SeekTable &object): Prototype(object) { }
+			inline SeekTable(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline SeekTable(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline SeekTable(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			~SeekTable();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline SeekTable &operator=(const SeekTable &object) { Prototype::operator=(object); return *this; }
+			inline SeekTable &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline SeekTable &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline SeekTable &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const SeekTable &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const SeekTable &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			uint32_t get_num_points() const;
+			::FLAC__StreamMetadata_SeekPoint get_point(uint32_t index) const;
+
+			//! See FLAC__metadata_object_seektable_resize_points()
+			bool resize_points(uint32_t new_num_points);
+
+			//! See FLAC__metadata_object_seektable_set_point()
+			void set_point(uint32_t index, const ::FLAC__StreamMetadata_SeekPoint &point);
+
+			//! See FLAC__metadata_object_seektable_insert_point()
+			bool insert_point(uint32_t index, const ::FLAC__StreamMetadata_SeekPoint &point);
+
+			//! See FLAC__metadata_object_seektable_delete_point()
+			bool delete_point(uint32_t index);
+
+			//! See FLAC__metadata_object_seektable_is_legal()
+			bool is_legal() const;
+
+			//! See FLAC__metadata_object_seektable_template_append_placeholders()
+			bool template_append_placeholders(uint32_t num);
+
+			//! See FLAC__metadata_object_seektable_template_append_point()
+			bool template_append_point(FLAC__uint64 sample_number);
+
+			//! See FLAC__metadata_object_seektable_template_append_points()
+			bool template_append_points(FLAC__uint64 sample_numbers[], uint32_t num);
+
+			//! See FLAC__metadata_object_seektable_template_append_spaced_points()
+			bool template_append_spaced_points(uint32_t num, FLAC__uint64 total_samples);
+
+			//! See FLAC__metadata_object_seektable_template_append_spaced_points_by_samples()
+			bool template_append_spaced_points_by_samples(uint32_t samples, FLAC__uint64 total_samples);
+
+			//! See FLAC__metadata_object_seektable_template_sort()
+			bool template_sort(bool compact);
+		};
+
+		/** VORBIS_COMMENT metadata block.
+		 *  See the \link flacpp_metadata_object overview \endlink for more,
+		 *  and the <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>.
+		 */
+		class FLACPP_API VorbisComment : public Prototype {
+		public:
+			/** Convenience class for encapsulating Vorbis comment
+			 *  entries.  An entry is a vendor string or a comment
+			 *  field.  In the case of a vendor string, the field
+			 *  name is undefined; only the field value is relevant.
+			 *
+			 *  A \a field as used in the methods refers to an
+			 *  entire 'NAME=VALUE' string; for convenience the
+			 *  string is NUL-terminated.  A length field is
+			 *  required in the unlikely event that the value
+			 *  contains contain embedded NULs.
+			 *
+			 *  A \a field_name is what is on the left side of the
+			 *  first '=' in the \a field.  By definition it is ASCII
+			 *  and so is NUL-terminated and does not require a
+			 *  length to describe it.  \a field_name is undefined
+			 *  for a vendor string entry.
+			 *
+			 *  A \a field_value is what is on the right side of the
+			 *  first '=' in the \a field.  By definition, this may
+			 *  contain embedded NULs and so a \a field_value_length
+			 *  is required to describe it.  However in practice,
+			 *  embedded NULs are not known to be used, so it is
+			 *  generally safe to treat field values as NUL-
+			 *  terminated UTF-8 strings.
+			 *
+			 *  Always check is_valid() after the constructor or operator=
+			 *  to make sure memory was properly allocated and that the
+			 *  Entry conforms to the Vorbis comment specification.
+			 */
+			class FLACPP_API Entry {
+			public:
+				Entry();
+
+				Entry(const char *field, uint32_t field_length);
+				Entry(const char *field); // assumes \a field is NUL-terminated
+
+				Entry(const char *field_name, const char *field_value, uint32_t field_value_length);
+				Entry(const char *field_name, const char *field_value); // assumes \a field_value is NUL-terminated
+
+				Entry(const Entry &entry);
+
+				Entry &operator=(const Entry &entry);
+
+				virtual ~Entry();
+
+				virtual bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+				uint32_t get_field_length() const;
+				uint32_t get_field_name_length() const;
+				uint32_t get_field_value_length() const;
+
+				::FLAC__StreamMetadata_VorbisComment_Entry get_entry() const;
+				const char *get_field() const;
+				const char *get_field_name() const;
+				const char *get_field_value() const;
+
+				bool set_field(const char *field, uint32_t field_length);
+				bool set_field(const char *field); // assumes \a field is NUL-terminated
+				bool set_field_name(const char *field_name);
+				bool set_field_value(const char *field_value, uint32_t field_value_length);
+				bool set_field_value(const char *field_value); // assumes \a field_value is NUL-terminated
+			protected:
+				bool is_valid_;
+				::FLAC__StreamMetadata_VorbisComment_Entry entry_;
+				char *field_name_;
+				uint32_t field_name_length_;
+				char *field_value_;
+				uint32_t field_value_length_;
+			private:
+				void zero();
+				void clear();
+				void clear_entry();
+				void clear_field_name();
+				void clear_field_value();
+				void construct(const char *field, uint32_t field_length);
+				void construct(const char *field); // assumes \a field is NUL-terminated
+				void construct(const char *field_name, const char *field_value, uint32_t field_value_length);
+				void construct(const char *field_name, const char *field_value); // assumes \a field_value is NUL-terminated
+				void compose_field();
+				void parse_field();
+			};
+
+			VorbisComment();
+
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline VorbisComment(const VorbisComment &object): Prototype(object) { }
+			inline VorbisComment(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline VorbisComment(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline VorbisComment(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			~VorbisComment();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline VorbisComment &operator=(const VorbisComment &object) { Prototype::operator=(object); return *this; }
+			inline VorbisComment &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline VorbisComment &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline VorbisComment &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const VorbisComment &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const VorbisComment &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			uint32_t get_num_comments() const;
+			const FLAC__byte *get_vendor_string() const; // NUL-terminated UTF-8 string
+			Entry get_comment(uint32_t index) const;
+
+			//! See FLAC__metadata_object_vorbiscomment_set_vendor_string()
+			bool set_vendor_string(const FLAC__byte *string); // NUL-terminated UTF-8 string
+
+			//! See FLAC__metadata_object_vorbiscomment_resize_comments()
+			bool resize_comments(uint32_t new_num_comments);
+
+			//! See FLAC__metadata_object_vorbiscomment_set_comment()
+			bool set_comment(uint32_t index, const Entry &entry);
+
+			//! See FLAC__metadata_object_vorbiscomment_insert_comment()
+			bool insert_comment(uint32_t index, const Entry &entry);
+
+			//! See FLAC__metadata_object_vorbiscomment_append_comment()
+			bool append_comment(const Entry &entry);
+
+			//! See FLAC__metadata_object_vorbiscomment_replace_comment()
+			bool replace_comment(const Entry &entry, bool all);
+
+			//! See FLAC__metadata_object_vorbiscomment_delete_comment()
+			bool delete_comment(uint32_t index);
+
+			//! See FLAC__metadata_object_vorbiscomment_find_entry_from()
+			int find_entry_from(uint32_t offset, const char *field_name);
+
+			//! See FLAC__metadata_object_vorbiscomment_remove_entry_matching()
+			int remove_entry_matching(const char *field_name);
+
+			//! See FLAC__metadata_object_vorbiscomment_remove_entries_matching()
+			int remove_entries_matching(const char *field_name);
+		};
+
+		/** CUESHEET metadata block.
+		 *  See the \link flacpp_metadata_object overview \endlink for more,
+		 *  and the <A HREF="../format.html#metadata_block_cuesheet">format specification</A>.
+		 */
+		class FLACPP_API CueSheet : public Prototype {
+		public:
+			/** Convenience class for encapsulating a cue sheet
+			 *  track.
+			 *
+			 *  Always check is_valid() after the constructor or operator=
+			 *  to make sure memory was properly allocated.
+			 */
+			class FLACPP_API Track {
+			protected:
+				::FLAC__StreamMetadata_CueSheet_Track *object_;
+			public:
+				Track();
+				Track(const ::FLAC__StreamMetadata_CueSheet_Track *track);
+				Track(const Track &track);
+				Track &operator=(const Track &track);
+
+				virtual ~Track();
+
+				virtual bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+
+				inline FLAC__uint64 get_offset() const { return object_->offset; }
+				inline FLAC__byte get_number() const { return object_->number; }
+				inline const char *get_isrc() const { return object_->isrc; }
+				inline uint32_t get_type() const { return object_->type; }
+				inline bool get_pre_emphasis() const { return object_->pre_emphasis; }
+
+				inline FLAC__byte get_num_indices() const { return object_->num_indices; }
+				::FLAC__StreamMetadata_CueSheet_Index get_index(uint32_t i) const;
+
+				inline const ::FLAC__StreamMetadata_CueSheet_Track *get_track() const { return object_; }
+
+				inline void set_offset(FLAC__uint64 value) { object_->offset = value; }
+				inline void set_number(FLAC__byte value) { object_->number = value; }
+				void set_isrc(const char value[12]);
+				void set_type(uint32_t value);
+				inline void set_pre_emphasis(bool value) { object_->pre_emphasis = value? 1 : 0; }
+
+ 				void set_index(uint32_t i, const ::FLAC__StreamMetadata_CueSheet_Index &index);
+				//@@@ It's awkward but to insert/delete index points
+				//@@@ you must use the routines in the CueSheet class.
+			};
+
+			CueSheet();
+
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline CueSheet(const CueSheet &object): Prototype(object) { }
+			inline CueSheet(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline CueSheet(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline CueSheet(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			~CueSheet();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline CueSheet &operator=(const CueSheet &object) { Prototype::operator=(object); return *this; }
+			inline CueSheet &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline CueSheet &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline CueSheet &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const CueSheet &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const CueSheet &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			const char *get_media_catalog_number() const;
+			FLAC__uint64 get_lead_in() const;
+			bool get_is_cd() const;
+
+			uint32_t get_num_tracks() const;
+			Track get_track(uint32_t i) const;
+
+			void set_media_catalog_number(const char value[128]);
+			void set_lead_in(FLAC__uint64 value);
+			void set_is_cd(bool value);
+
+			void set_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index);
+
+			//! See FLAC__metadata_object_cuesheet_track_resize_indices()
+			bool resize_indices(uint32_t track_num, uint32_t new_num_indices);
+
+			//! See FLAC__metadata_object_cuesheet_track_insert_index()
+			bool insert_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index);
+
+			//! See FLAC__metadata_object_cuesheet_track_insert_blank_index()
+			bool insert_blank_index(uint32_t track_num, uint32_t index_num);
+
+			//! See FLAC__metadata_object_cuesheet_track_delete_index()
+			bool delete_index(uint32_t track_num, uint32_t index_num);
+
+			//! See FLAC__metadata_object_cuesheet_resize_tracks()
+			bool resize_tracks(uint32_t new_num_tracks);
+
+			//! See FLAC__metadata_object_cuesheet_set_track()
+			bool set_track(uint32_t i, const Track &track);
+
+			//! See FLAC__metadata_object_cuesheet_insert_track()
+			bool insert_track(uint32_t i, const Track &track);
+
+			//! See FLAC__metadata_object_cuesheet_insert_blank_track()
+			bool insert_blank_track(uint32_t i);
+
+			//! See FLAC__metadata_object_cuesheet_delete_track()
+			bool delete_track(uint32_t i);
+
+			//! See FLAC__metadata_object_cuesheet_is_legal()
+			bool is_legal(bool check_cd_da_subset = false, const char **violation = 0) const;
+
+			//! See FLAC__metadata_object_cuesheet_calculate_cddb_id()
+			FLAC__uint32 calculate_cddb_id() const;
+		};
+
+		/** PICTURE metadata block.
+		 *  See the \link flacpp_metadata_object overview \endlink for more,
+		 *  and the <A HREF="../format.html#metadata_block_picture">format specification</A>.
+		 */
+		class FLACPP_API Picture : public Prototype {
+		public:
+			Picture();
+
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline Picture(const Picture &object): Prototype(object) { }
+			inline Picture(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline Picture(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Picture(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			~Picture();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline Picture &operator=(const Picture &object) { Prototype::operator=(object); return *this; }
+			inline Picture &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline Picture &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Picture &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const Picture &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const Picture &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			::FLAC__StreamMetadata_Picture_Type get_type() const;
+			const char *get_mime_type() const; // NUL-terminated printable ASCII string
+			const FLAC__byte *get_description() const; // NUL-terminated UTF-8 string
+			FLAC__uint32 get_width() const;
+			FLAC__uint32 get_height() const;
+			FLAC__uint32 get_depth() const;
+			FLAC__uint32 get_colors() const; ///< a return value of \c 0 means true-color, i.e. 2^depth colors
+			FLAC__uint32 get_data_length() const;
+			const FLAC__byte *get_data() const;
+
+			void set_type(::FLAC__StreamMetadata_Picture_Type type);
+
+			//! See FLAC__metadata_object_picture_set_mime_type()
+			bool set_mime_type(const char *string); // NUL-terminated printable ASCII string
+
+			//! See FLAC__metadata_object_picture_set_description()
+			bool set_description(const FLAC__byte *string); // NUL-terminated UTF-8 string
+
+			void set_width(FLAC__uint32 value) const;
+			void set_height(FLAC__uint32 value) const;
+			void set_depth(FLAC__uint32 value) const;
+			void set_colors(FLAC__uint32 value) const; ///< a value of \c 0 means true-color, i.e. 2^depth colors
+
+			//! See FLAC__metadata_object_picture_set_data()
+			bool set_data(const FLAC__byte *data, FLAC__uint32 data_length);
+
+			//! See FLAC__metadata_object_picture_is_legal()
+			bool is_legal(const char **violation);
+		};
+
+		/** Opaque metadata block for storing unknown types.
+		 *  This should not be used unless you know what you are doing;
+		 *  it is currently used only internally to support forward
+		 *  compatibility of metadata blocks.
+		 *  See the \link flacpp_metadata_object overview \endlink for more,
+		 */
+		class FLACPP_API Unknown : public Prototype {
+		public:
+			Unknown();
+			//
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline Unknown(const Unknown &object): Prototype(object) { }
+			inline Unknown(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline Unknown(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Unknown(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			~Unknown();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline Unknown &operator=(const Unknown &object) { Prototype::operator=(object); return *this; }
+			inline Unknown &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline Unknown &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Unknown &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const Unknown &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const Unknown &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			const FLAC__byte *get_data() const;
+
+			//! This form always copies \a data
+			bool set_data(const FLAC__byte *data, uint32_t length);
+			bool set_data(FLAC__byte *data, uint32_t length, bool copy);
+		};
+
+		/* \} */
+
+
+		/** \defgroup flacpp_metadata_level0 FLAC++/metadata.h: metadata level 0 interface
+		 *  \ingroup flacpp_metadata
+		 *
+		 *  \brief
+		 *  Level 0 metadata iterators.
+		 *
+		 *  See the \link flac_metadata_level0 C layer equivalent \endlink
+		 *  for more.
+		 *
+		 * \{
+		 */
+
+		FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo); ///< See FLAC__metadata_get_streaminfo().
+
+		FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags); ///< See FLAC__metadata_get_tags().
+		FLACPP_API bool get_tags(const char *filename, VorbisComment &tags); ///< See FLAC__metadata_get_tags().
+
+		FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet); ///< See FLAC__metadata_get_cuesheet().
+		FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet); ///< See FLAC__metadata_get_cuesheet().
+
+		FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors); ///< See FLAC__metadata_get_picture().
+		FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors); ///< See FLAC__metadata_get_picture().
+
+		/* \} */
+
+
+		/** \defgroup flacpp_metadata_level1 FLAC++/metadata.h: metadata level 1 interface
+		 *  \ingroup flacpp_metadata
+		 *
+		 *  \brief
+		 *  Level 1 metadata iterator.
+		 *
+		 *  The flow through the iterator in the C++ layer is similar
+		 *  to the C layer:
+		 *    - Create a SimpleIterator instance
+		 *    - Check SimpleIterator::is_valid()
+		 *    - Call SimpleIterator::init() and check the return
+		 *    - Traverse and/or edit.  Edits are written to file
+		 *      immediately.
+		 *    - Destroy the SimpleIterator instance
+		 *
+		 *  The ownership of pointers in the C++ layer follows that in
+		 *  the C layer, i.e.
+		 *    - The objects returned by get_block() are yours to
+		 *      modify, but changes are not reflected in the FLAC file
+		 *      until you call set_block().  The objects are also
+		 *      yours to delete; they are not automatically deleted
+		 *      when passed to set_block() or insert_block_after().
+		 *
+		 *  See the \link flac_metadata_level1 C layer equivalent \endlink
+		 *  for more.
+		 *
+		 * \{
+		 */
+
+		/** This class is a wrapper around the FLAC__metadata_simple_iterator
+		 *  structures and methods; see the
+		 * \link flacpp_metadata_level1 usage guide \endlink and
+		 * ::FLAC__Metadata_SimpleIterator.
+		 */
+		class FLACPP_API SimpleIterator {
+		public:
+			/** This class is a wrapper around FLAC__Metadata_SimpleIteratorStatus.
+			 */
+			class FLACPP_API Status {
+			public:
+				inline Status(::FLAC__Metadata_SimpleIteratorStatus status): status_(status) { }
+				inline operator ::FLAC__Metadata_SimpleIteratorStatus() const { return status_; }
+				inline const char *as_cstring() const { return ::FLAC__Metadata_SimpleIteratorStatusString[status_]; }
+			protected:
+				::FLAC__Metadata_SimpleIteratorStatus status_;
+			};
+
+			SimpleIterator();
+			virtual ~SimpleIterator();
+
+			bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+			bool init(const char *filename, bool read_only, bool preserve_file_stats); ///< See FLAC__metadata_simple_iterator_init().
+
+			Status status();                                                    ///< See FLAC__metadata_simple_iterator_status().
+			bool is_writable() const;                                           ///< See FLAC__metadata_simple_iterator_is_writable().
+
+			bool next();                                                        ///< See FLAC__metadata_simple_iterator_next().
+			bool prev();                                                        ///< See FLAC__metadata_simple_iterator_prev().
+			bool is_last() const;                                               ///< See FLAC__metadata_simple_iterator_is_last().
+
+			off_t get_block_offset() const;                                     ///< See FLAC__metadata_simple_iterator_get_block_offset().
+			::FLAC__MetadataType get_block_type() const;                        ///< See FLAC__metadata_simple_iterator_get_block_type().
+			uint32_t get_block_length() const;                                  ///< See FLAC__metadata_simple_iterator_get_block_length().
+			bool get_application_id(FLAC__byte *id);                            ///< See FLAC__metadata_simple_iterator_get_application_id().
+			Prototype *get_block();                                             ///< See FLAC__metadata_simple_iterator_get_block().
+			bool set_block(Prototype *block, bool use_padding = true);          ///< See FLAC__metadata_simple_iterator_set_block().
+			bool insert_block_after(Prototype *block, bool use_padding = true); ///< See FLAC__metadata_simple_iterator_insert_block_after().
+			bool delete_block(bool use_padding = true);                         ///< See FLAC__metadata_simple_iterator_delete_block().
+
+		protected:
+			::FLAC__Metadata_SimpleIterator *iterator_;
+			void clear();
+
+		private: // Do not use.
+			SimpleIterator(const SimpleIterator&);
+			SimpleIterator&operator=(const SimpleIterator&);
+		};
+
+		/* \} */
+
+
+		/** \defgroup flacpp_metadata_level2 FLAC++/metadata.h: metadata level 2 interface
+		 *  \ingroup flacpp_metadata
+		 *
+		 *  \brief
+		 *  Level 2 metadata iterator.
+		 *
+		 *  The flow through the iterator in the C++ layer is similar
+		 *  to the C layer:
+		 *    - Create a Chain instance
+		 *    - Check Chain::is_valid()
+		 *    - Call Chain::read() and check the return
+		 *    - Traverse and/or edit with an Iterator or with
+		 *      Chain::merge_padding() or Chain::sort_padding()
+		 *    - Write changes back to FLAC file with Chain::write()
+		 *    - Destroy the Chain instance
+		 *
+		 *  The ownership of pointers in the C++ layer is slightly
+		 *  different than in the C layer, i.e.
+		 *    - The objects returned by Iterator::get_block() are NOT
+		 *      owned by the iterator and should be deleted by the
+		 *      caller when finished, BUT, when you modify the block,
+		 *      it will directly edit what's in the chain and you do
+		 *      not need to call Iterator::set_block().  However the
+		 *      changes will not be reflected in the FLAC file until
+		 *      the chain is written with Chain::write().
+		 *    - When you pass an object to Iterator::set_block(),
+		 *      Iterator::insert_block_before(), or
+		 *      Iterator::insert_block_after(), the iterator takes
+		 *      ownership of the block and it will be deleted by the
+		 *      chain.
+		 *
+		 *  See the \link flac_metadata_level2 C layer equivalent \endlink
+		 *  for more.
+		 *
+		 * \{
+		 */
+
+		/** This class is a wrapper around the FLAC__metadata_chain
+		 *  structures and methods; see the
+		 * \link flacpp_metadata_level2 usage guide \endlink and
+		 * ::FLAC__Metadata_Chain.
+		 */
+		class FLACPP_API Chain {
+		public:
+			/** This class is a wrapper around FLAC__Metadata_ChainStatus.
+			 */
+			class FLACPP_API Status {
+			public:
+				inline Status(::FLAC__Metadata_ChainStatus status): status_(status) { }
+				inline operator ::FLAC__Metadata_ChainStatus() const { return status_; }
+				inline const char *as_cstring() const { return ::FLAC__Metadata_ChainStatusString[status_]; }
+			protected:
+				::FLAC__Metadata_ChainStatus status_;
+			};
+
+			Chain();
+			virtual ~Chain();
+
+			friend class Iterator;
+
+			bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+			Status status();                                                ///< See FLAC__metadata_chain_status().
+
+			bool read(const char *filename, bool is_ogg = false);                                ///< See FLAC__metadata_chain_read(), FLAC__metadata_chain_read_ogg().
+			bool read(FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, bool is_ogg = false);  ///< See FLAC__metadata_chain_read_with_callbacks(), FLAC__metadata_chain_read_ogg_with_callbacks().
+
+			bool check_if_tempfile_needed(bool use_padding);                ///< See FLAC__metadata_chain_check_if_tempfile_needed().
+
+			bool write(bool use_padding = true, bool preserve_file_stats = false); ///< See FLAC__metadata_chain_write().
+			bool write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks); ///< See FLAC__metadata_chain_write_with_callbacks().
+			bool write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks); ///< See FLAC__metadata_chain_write_with_callbacks_and_tempfile().
+
+			void merge_padding();                                           ///< See FLAC__metadata_chain_merge_padding().
+			void sort_padding();                                            ///< See FLAC__metadata_chain_sort_padding().
+
+		protected:
+			::FLAC__Metadata_Chain *chain_;
+			virtual void clear();
+
+		private: // Do not use.
+			Chain(const Chain&);
+			Chain&operator=(const Chain&);
+		};
+
+		/** This class is a wrapper around the FLAC__metadata_iterator
+		 *  structures and methods; see the
+		 * \link flacpp_metadata_level2 usage guide \endlink and
+		 * ::FLAC__Metadata_Iterator.
+		 */
+		class FLACPP_API Iterator {
+		public:
+			Iterator();
+			virtual ~Iterator();
+
+			bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+
+			void init(Chain &chain);                       ///< See FLAC__metadata_iterator_init().
+
+			bool next();                                   ///< See FLAC__metadata_iterator_next().
+			bool prev();                                   ///< See FLAC__metadata_iterator_prev().
+
+			::FLAC__MetadataType get_block_type() const;   ///< See FLAC__metadata_iterator_get_block_type().
+			Prototype *get_block();                        ///< See FLAC__metadata_iterator_get_block().
+			bool set_block(Prototype *block);              ///< See FLAC__metadata_iterator_set_block().
+			bool delete_block(bool replace_with_padding);  ///< See FLAC__metadata_iterator_delete_block().
+			bool insert_block_before(Prototype *block);    ///< See FLAC__metadata_iterator_insert_block_before().
+			bool insert_block_after(Prototype *block);     ///< See FLAC__metadata_iterator_insert_block_after().
+
+		protected:
+			::FLAC__Metadata_Iterator *iterator_;
+			virtual void clear();
+
+		private: // Do not use.
+			Iterator(const Iterator&);
+			Iterator&operator=(const Iterator&);
+		};
+
+		/* \} */
+
+	}
+}
+
+#endif
diff --git a/include/FLAC/Makefile.am b/include/FLAC/Makefile.am
new file mode 100644
index 0000000..82aca28
--- /dev/null
+++ b/include/FLAC/Makefile.am
@@ -0,0 +1,43 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+flaccincludedir = $(includedir)/FLAC
+
+flaccinclude_HEADERS = \
+	all.h \
+	assert.h \
+	callback.h \
+	export.h \
+	format.h \
+	metadata.h \
+	ordinals.h \
+	stream_decoder.h \
+	stream_encoder.h
diff --git a/include/FLAC/all.h b/include/FLAC/all.h
index 11d47d7..6ba03c1 100644
--- a/include/FLAC/all.h
+++ b/include/FLAC/all.h
@@ -147,7 +147,7 @@
  * 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
+ * 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.
  */
@@ -159,9 +159,9 @@
  * 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
+ * in FLAC 1.1.3 is a set of \#defines in \c export.h of each
  * library's includes (e.g. \c include/FLAC/export.h).  The
- * \c #defines mirror the libraries'
+ * \#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.
@@ -321,7 +321,7 @@
  *
  * The \a bytes parameter to FLAC__StreamDecoderReadCallback,
  * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback
- * is now \c size_t instead of \c unsigned.
+ * is now \c size_t instead of \c uint32_t.
  */
 
 /** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4
diff --git a/include/FLAC/assert.h b/include/FLAC/assert.h
index b546fd0..55b3477 100644
--- a/include/FLAC/assert.h
+++ b/include/FLAC/assert.h
@@ -34,7 +34,7 @@
 #define FLAC__ASSERT_H
 
 /* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */
-#ifdef DEBUG
+#ifndef NDEBUG
 #include <assert.h>
 #define FLAC__ASSERT(x) assert(x)
 #define FLAC__ASSERT_DECLARATION(x) x
diff --git a/include/FLAC/callback.h b/include/FLAC/callback.h
index f942dd2..38e2300 100644
--- a/include/FLAC/callback.h
+++ b/include/FLAC/callback.h
@@ -165,7 +165,7 @@
  *  required may be set to NULL.
  *
  *  If the seek requirement for an interface is optional, you can signify that
- *  a data sorce is not seekable by setting the \a seek field to \c NULL.
+ *  a data source is not seekable by setting the \a seek field to \c NULL.
  */
 typedef struct {
 	FLAC__IOCallback_Read read;
diff --git a/include/FLAC/export.h b/include/FLAC/export.h
index d52f0bb..3e3e764 100644
--- a/include/FLAC/export.h
+++ b/include/FLAC/export.h
@@ -36,7 +36,7 @@
 /** \file include/FLAC/export.h
  *
  *  \brief
- *  This module contains #defines and symbols for exporting function
+ *  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.
@@ -46,7 +46,7 @@
  *  \ingroup flac
  *
  *  \brief
- *  This module contains #defines and symbols for exporting function
+ *  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
@@ -59,7 +59,7 @@
 #if defined(FLAC__NO_DLL)
 #define FLAC_API
 
-#elif defined(_MSC_VER)
+#elif defined(_WIN32)
 #ifdef FLAC_API_EXPORTS
 #define	FLAC_API __declspec(dllexport)
 #else
@@ -74,7 +74,7 @@
 
 #endif
 
-/** These #defines will mirror the libtool-based library version number, see
+/** 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
diff --git a/include/FLAC/format.h b/include/FLAC/format.h
index c087d4a..769ab8a 100644
--- a/include/FLAC/format.h
+++ b/include/FLAC/format.h
@@ -173,10 +173,10 @@
 /** The 32-bit integer big-endian representation of the beginning of
  *  a FLAC stream.
  */
-extern FLAC_API const unsigned FLAC__STREAM_SYNC; /* = 0x664C6143 */
+extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */
 
 /** The length of the FLAC signature in bits. */
-extern FLAC_API const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */
+extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */
 
 /** The length of the FLAC signature in bytes. */
 #define FLAC__STREAM_SYNC_LENGTH (4u)
@@ -213,15 +213,15 @@
  */
 typedef struct {
 
-	unsigned *parameters;
+	uint32_t *parameters;
 	/**< The Rice parameters for each context. */
 
-	unsigned *raw_bits;
+	uint32_t *raw_bits;
 	/**< Widths for escape-coded partitions.  Will be non-zero for escaped
 	 * partitions and zero for unescaped partitions.
 	 */
 
-	unsigned capacity_by_order;
+	uint32_t capacity_by_order;
 	/**< The capacity of the \a parameters and \a raw_bits arrays
 	 * specified as an order, i.e. the number of array elements
 	 * allocated is 2 ^ \a capacity_by_order.
@@ -232,7 +232,7 @@
  */
 typedef struct {
 
-	unsigned order;
+	uint32_t order;
 	/**< The partition order, i.e. # of contexts = 2 ^ \a order. */
 
 	const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
@@ -240,14 +240,14 @@
 
 } FLAC__EntropyCodingMethod_PartitionedRice;
 
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
 
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+extern FLAC_API const uint32_t 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;
+extern FLAC_API const uint32_t 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>)
@@ -259,7 +259,7 @@
 	} data;
 } FLAC__EntropyCodingMethod;
 
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
 
 /*****************************************************************************/
 
@@ -299,7 +299,7 @@
 	FLAC__EntropyCodingMethod entropy_coding_method;
 	/**< The residual coding method. */
 
-	unsigned order;
+	uint32_t order;
 	/**< The polynomial order. */
 
 	FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];
@@ -316,10 +316,10 @@
 	FLAC__EntropyCodingMethod entropy_coding_method;
 	/**< The residual coding method. */
 
-	unsigned order;
+	uint32_t order;
 	/**< The FIR order. */
 
-	unsigned qlp_coeff_precision;
+	uint32_t qlp_coeff_precision;
 	/**< Quantized FIR filter coefficient precision in bits. */
 
 	int quantization_level;
@@ -335,8 +335,8 @@
 	/**< The residual signal, length == (blocksize minus order) samples. */
 } FLAC__Subframe_LPC;
 
-extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
 
 
 /** FLAC subframe structure.  (c.f. <A HREF="../format.html#subframe">format specification</A>)
@@ -349,7 +349,7 @@
 		FLAC__Subframe_LPC lpc;
 		FLAC__Subframe_Verbatim verbatim;
 	} data;
-	unsigned wasted_bits;
+	uint32_t wasted_bits;
 } FLAC__Subframe;
 
 /** == 1 (bit)
@@ -359,14 +359,14 @@
  * 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 uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN;
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
+extern FLAC_API const uint32_t 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 uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
 
 /*****************************************************************************/
 
@@ -409,19 +409,19 @@
 /** FLAC frame header structure.  (c.f. <A HREF="../format.html#frame_header">format specification</A>)
  */
 typedef struct {
-	unsigned blocksize;
+	uint32_t blocksize;
 	/**< The number of samples per subframe. */
 
-	unsigned sample_rate;
+	uint32_t sample_rate;
 	/**< The sample rate in Hz. */
 
-	unsigned channels;
+	uint32_t channels;
 	/**< The number of channels (== number of subframes). */
 
 	FLAC__ChannelAssignment channel_assignment;
 	/**< The channel assignment for the frame. */
 
-	unsigned bits_per_sample;
+	uint32_t bits_per_sample;
 	/**< The sample resolution. */
 
 	FLAC__FrameNumberType number_type;
@@ -443,16 +443,16 @@
 	 */
 } FLAC__FrameHeader;
 
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 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) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
 
 
 /** FLAC frame footer structure.  (c.f. <A HREF="../format.html#frame_footer">format specification</A>)
@@ -465,7 +465,7 @@
 	 */
 } FLAC__FrameFooter;
 
-extern FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
 
 
 /** FLAC frame structure.  (c.f. <A HREF="../format.html#frame">format specification</A>)
@@ -527,24 +527,24 @@
 /** FLAC STREAMINFO structure.  (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
  */
 typedef struct {
-	unsigned min_blocksize, max_blocksize;
-	unsigned min_framesize, max_framesize;
-	unsigned sample_rate;
-	unsigned channels;
-	unsigned bits_per_sample;
+	uint32_t min_blocksize, max_blocksize;
+	uint32_t min_framesize, max_framesize;
+	uint32_t sample_rate;
+	uint32_t channels;
+	uint32_t bits_per_sample;
 	FLAC__uint64 total_samples;
 	FLAC__byte md5sum[16];
 } FLAC__StreamMetadata_StreamInfo;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
 
 /** The total stream length of the STREAMINFO block in bytes. */
 #define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u)
@@ -567,7 +567,7 @@
 	FLAC__byte *data;
 } FLAC__StreamMetadata_Application;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
 
 /** SeekPoint structure used in SEEKTABLE blocks.  (c.f. <A HREF="../format.html#seekpoint">format specification</A>)
  */
@@ -579,13 +579,13 @@
 	/**< The offset, in bytes, of the target frame with respect to
 	 * beginning of the first frame. */
 
-	unsigned frame_samples;
+	uint32_t frame_samples;
 	/**< The number of samples in the target frame. */
 } FLAC__StreamMetadata_SeekPoint;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
 
 /** The total stream length of a seek point in bytes. */
 #define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u)
@@ -610,7 +610,7 @@
  *   present in a stream.
  */
 typedef struct {
-	unsigned num_points;
+	uint32_t num_points;
 	FLAC__StreamMetadata_SeekPoint *points;
 } FLAC__StreamMetadata_SeekTable;
 
@@ -626,7 +626,7 @@
 	FLAC__byte *entry;
 } FLAC__StreamMetadata_VorbisComment_Entry;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
 
 
 /** FLAC VORBIS_COMMENT structure.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
@@ -637,7 +637,7 @@
 	FLAC__StreamMetadata_VorbisComment_Entry *comments;
 } FLAC__StreamMetadata_VorbisComment;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
 
 
 /** FLAC CUESHEET track index structure.  (See the
@@ -654,9 +654,9 @@
 	/**< The index point number. */
 } FLAC__StreamMetadata_CueSheet_Index;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
 
 
 /** FLAC CUESHEET track structure.  (See the
@@ -673,10 +673,10 @@
 	char isrc[13];
 	/**< Track ISRC.  This is a 12-digit alphanumeric code plus a trailing \c NUL byte */
 
-	unsigned type:1;
+	uint32_t type:1;
 	/**< The track type: 0 for audio, 1 for non-audio. */
 
-	unsigned pre_emphasis:1;
+	uint32_t pre_emphasis:1;
 	/**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */
 
 	FLAC__byte num_indices;
@@ -687,13 +687,13 @@
 
 } FLAC__StreamMetadata_CueSheet_Track;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
 
 
 /** FLAC CUESHEET structure.  (See the
@@ -713,7 +713,7 @@
 	FLAC__bool is_cd;
 	/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
 
-	unsigned num_tracks;
+	uint32_t num_tracks;
 	/**< The number of tracks. */
 
 	FLAC__StreamMetadata_CueSheet_Track *tracks;
@@ -721,11 +721,11 @@
 
 } FLAC__StreamMetadata_CueSheet;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
 
 
 /** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
@@ -810,14 +810,14 @@
 
 } 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) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
 
 
 /** Structure that is used when a metadata block of unknown type is loaded.
@@ -840,7 +840,7 @@
 	FLAC__bool is_last;
 	/**< \c true if this metadata block is the last, else \a false */
 
-	unsigned length;
+	uint32_t length;
 	/**< Length, in bytes, of the block data as it appears in the stream. */
 
 	union {
@@ -857,9 +857,9 @@
 	 * to use. */
 } FLAC__StreamMetadata;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
 
 /** The total stream length of a metadata block header in bytes. */
 #define FLAC__STREAM_METADATA_HEADER_LENGTH (4u)
@@ -880,7 +880,7 @@
  *    \c true if the given sample rate conforms to the specification, else
  *    \c false.
  */
-FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate);
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate);
 
 /** Tests that a blocksize at the given sample rate is valid for the FLAC
  *  subset.
@@ -892,7 +892,7 @@
  *    \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);
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t 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
@@ -903,7 +903,7 @@
  *    \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);
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate);
 
 /** Check a Vorbis comment entry name to see if it conforms to the Vorbis
  *  comment specification.
@@ -926,14 +926,14 @@
  *
  * \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
+ *                   \c (uint32_t)(-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);
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length);
 
 /** Check a Vorbis comment entry to see if it conforms to the Vorbis
  *  comment specification.
@@ -950,7 +950,7 @@
  * \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);
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t 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
@@ -973,10 +973,10 @@
  * \param seek_table  A pointer to a seek table to be sorted.
  * \assert
  *    \code seek_table != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    The number of duplicate seek points converted into placeholders.
  */
-FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
+FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
 
 /** Check a cue sheet to see if it conforms to the FLAC specification.
  *  See the format specification for limits on the contents of the
diff --git a/include/FLAC/metadata.h b/include/FLAC/metadata.h
index 4e18cd6..4c67b87 100644
--- a/include/FLAC/metadata.h
+++ b/include/FLAC/metadata.h
@@ -93,7 +93,7 @@
  *  Efficient means the whole file is rewritten at most one time, and only
  *  when necessary.  Level 1 is not efficient only in the case that you
  *  cause more than one metadata block to grow or shrink beyond what can
- *  be accomodated by padding.  In this case you should probably use level
+ *  be accommodated by padding.  In this case you should probably use level
  *  2, which allows you to edit all the metadata for a file in memory and
  *  write it out all at once.
  *
@@ -217,13 +217,13 @@
  *                    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".
+ *                    \c (uint32_t)(-1) to mean "any width".
  * \param max_height  The maximum height in pixels desired.  Use
- *                    \c (unsigned)(-1) to mean "any height".
+ *                    \c (uint32_t)(-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".
+ *                    Use \c (uint32_t)(-1) to mean "any depth".
  * \param max_colors  The maximum number of colors desired.  Use
- *                    \c (unsigned)(-1) to mean "any number of colors".
+ *                    \c (uint32_t)(-1) to mean "any number of colors".
  * \assert
  *    \code filename != NULL \endcode
  *    \code picture != NULL \endcode
@@ -234,7 +234,7 @@
  *    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);
+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, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors);
 
 /* \} */
 
@@ -497,13 +497,13 @@
  *    \code iterator != NULL \endcode
  *    \a iterator has been successfully initialized with
  *    FLAC__metadata_simple_iterator_init()
- * \retval unsigned
+ * \retval uint32_t
  *    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);
+FLAC_API uint32_t 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
@@ -1373,7 +1373,7 @@
  * \retval FLAC__bool
  *    \c false if \a copy is \c true and malloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy);
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy);
 
 /** Resize the seekpoint array.
  *
@@ -1390,7 +1390,7 @@
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points);
 
 /** Set a seekpoint in a seektable.
  *
@@ -1402,7 +1402,7 @@
  *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
  *    \code object->data.seek_table.num_points > point_num \endcode
  */
-FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
 
 /** Insert a seekpoint into a seektable.
  *
@@ -1416,7 +1416,7 @@
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
 
 /** Delete a seekpoint from a seektable.
  *
@@ -1429,7 +1429,7 @@
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num);
 
 /** Check a seektable to see if it conforms to the FLAC specification.
  *  See the format specification for limits on the contents of the
@@ -1459,7 +1459,7 @@
  * \retval FLAC__bool
  *    \c false if memory allocation fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num);
 
 /** Append a specific seek point template to the end of a seek table.
  *
@@ -1494,7 +1494,7 @@
  * \retval FLAC__bool
  *    \c false if memory allocation fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num);
 
 /** Append a set of evenly-spaced seek point templates to the end of a
  *  seek table.
@@ -1516,7 +1516,7 @@
  * \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);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples);
 
 /** Append a set of evenly-spaced seek point templates to the end of a
  *  seek table.
@@ -1544,7 +1544,7 @@
  * \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);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples);
 
 /** Sort a seek table's seek points according to the format specification,
  *  removing duplicates.
@@ -1603,7 +1603,7 @@
  * \retval FLAC__bool
  *    \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);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments);
 
 /** Sets a comment in a VORBIS_COMMENT block.
  *
@@ -1630,7 +1630,7 @@
  *    \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);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
 
 /** Insert a comment in a VORBIS_COMMENT block at the given index.
  *
@@ -1660,7 +1660,7 @@
  *    \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);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
 
 /** Appends a comment to a VORBIS_COMMENT block.
  *
@@ -1733,7 +1733,7 @@
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num);
 
 /** Creates a Vorbis comment entry from NUL-terminated name and value strings.
  *
@@ -1789,7 +1789,7 @@
  * \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, uint32_t field_name_length);
 
 /** Find a Vorbis comment with the given field name.
  *
@@ -1808,7 +1808,7 @@
  *    The offset in the comment array of the first comment whose field
  *    name matches \a field_name, or \c -1 if no match was found.
  */
-FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name);
 
 /** Remove first Vorbis comment matching the given field name.
  *
@@ -1886,7 +1886,7 @@
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices);
 
 /** Insert an index point in a CUESHEET track at the given index.
  *
@@ -1909,7 +1909,7 @@
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index index);
 
 /** Insert a blank index point in a CUESHEET track at the given index.
  *
@@ -1933,7 +1933,7 @@
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
 
 /** Delete an index point in a CUESHEET track at the given index.
  *
@@ -1952,7 +1952,7 @@
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
 
 /** Resize the track array.
  *
@@ -1969,7 +1969,7 @@
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks);
 
 /** Sets a track in a CUESHEET block.
  *
@@ -1991,7 +1991,7 @@
  * \retval FLAC__bool
  *    \c false if \a copy is \c true and malloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
 
 /** Insert a track in a CUESHEET block at the given index.
  *
@@ -2014,7 +2014,7 @@
  * \retval FLAC__bool
  *    \c false if \a copy is \c true and malloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
 
 /** Insert a blank track in a CUESHEET block at the given index.
  *
@@ -2033,7 +2033,7 @@
  * \retval FLAC__bool
  *    \c false if \a copy is \c true and malloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num);
 
 /** Delete a track in a CUESHEET block at the given index.
  *
@@ -2048,7 +2048,7 @@
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num);
 
 /** Check a cue sheet to see if it conforms to the FLAC specification.
  *  See the format specification for limits on the contents of the
diff --git a/include/FLAC/ordinals.h b/include/FLAC/ordinals.h
index ea52ea6..75b830d 100644
--- a/include/FLAC/ordinals.h
+++ b/include/FLAC/ordinals.h
@@ -39,12 +39,11 @@
  * the 1999 ISO C Standard header file <stdint.h>.
  */
 
-typedef __int8 FLAC__int8;
+typedef signed __int8 FLAC__int8;
+typedef signed __int16 FLAC__int16;
+typedef signed __int32 FLAC__int32;
+typedef signed __int64 FLAC__int64;
 typedef unsigned __int8 FLAC__uint8;
-
-typedef __int16 FLAC__int16;
-typedef __int32 FLAC__int32;
-typedef __int64 FLAC__int64;
 typedef unsigned __int16 FLAC__uint16;
 typedef unsigned __int32 FLAC__uint32;
 typedef unsigned __int64 FLAC__uint64;
diff --git a/include/FLAC/stream_decoder.h b/include/FLAC/stream_decoder.h
index 39c958d..50ebfa8 100644
--- a/include/FLAC/stream_decoder.h
+++ b/include/FLAC/stream_decoder.h
@@ -920,7 +920,7 @@
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
 FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder);
@@ -932,10 +932,10 @@
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
-FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
+FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
 
 /** Get the current channel assignment in the stream being decoded.
  *  Will only be valid after decoding has started and will contain the
@@ -956,10 +956,10 @@
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
-FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
+FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
 
 /** Get the current sample rate in Hz of the stream being decoded.
  *  Will only be valid after decoding has started and will contain the
@@ -968,10 +968,10 @@
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
-FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
+FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
 
 /** Get the current blocksize of the stream being decoded.
  *  Will only be valid after decoding has started and will contain the
@@ -980,10 +980,10 @@
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
-FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
+FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
 
 /** Returns the decoder's current read position within the stream.
  *  The position is the byte offset from the start of the stream.
@@ -1184,7 +1184,7 @@
  *                            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.
+ *                            decoding from \c stdin 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
@@ -1234,7 +1234,7 @@
  *                            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.
+ *                            decoding from \c stdin 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
@@ -1403,8 +1403,7 @@
  *  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.
+ *  the stream on the next FLAC__stream_decoder_process_*() call.
  *
  * \param  decoder  A decoder instance.
  * \assert
@@ -1551,6 +1550,16 @@
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample);
 
+/** Return client_data from decoder.
+ *  The data pointed to by the pointer should not be modified.
+ *
+ * \param  decoder  A decoder instance.
+ * \retval const void *
+ *    The callee's client data set through FLAC__stream_decoder_init_*().
+ *    Do not modify the contents.
+ */
+FLAC_API const void *FLAC__get_decoder_client_data(FLAC__StreamDecoder *decoder);
+
 /* \} */
 
 #ifdef __cplusplus
diff --git a/include/FLAC/stream_encoder.h b/include/FLAC/stream_encoder.h
index 40a2fd3..d154ac4 100644
--- a/include/FLAC/stream_encoder.h
+++ b/include/FLAC/stream_encoder.h
@@ -554,7 +554,7 @@
  * \retval FLAC__StreamEncoderWriteStatus
  *    The callee's return status.
  */
-typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t 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, uint32_t samples, uint32_t current_frame, void *client_data);
 
 /** Signature for the seek callback.
  *
@@ -675,7 +675,7 @@
  * \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);
+typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data);
 
 
 /***********************************************************************
@@ -771,7 +771,7 @@
  * \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_channels(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the sample resolution of the input to be encoded.
  *
@@ -787,7 +787,7 @@
  * \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_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the sample rate (in Hz) of the input to be encoded.
  *
@@ -799,7 +799,7 @@
  * \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_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the compression level
  *
@@ -862,7 +862,7 @@
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the blocksize to use while encoding.
  *
@@ -877,13 +877,13 @@
  * \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_blocksize(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** 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 false
+ * \default \c true
  * \param  encoder  An encoder instance to set.
  * \param  value    Flag value (see above).
  * \assert
@@ -977,7 +977,7 @@
 
 /** Set the maximum LPC order, or \c 0 to use only the fixed predictors.
  *
- * \default \c 0
+ * \default \c 8
  * \param  encoder  An encoder instance to set.
  * \param  value    See above.
  * \assert
@@ -985,7 +985,7 @@
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the precision, in bits, of the quantized linear predictor
  *  coefficients, or \c 0 to let the encoder select it based on the
@@ -1003,7 +1003,7 @@
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set to \c false to use only the specified quantized linear predictor
  *  coefficient precision, or \c true to search neighboring precision
@@ -1066,7 +1066,7 @@
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the maximum partition order to search when coding the residual.
  *  This is used in tandem with
@@ -1081,7 +1081,7 @@
  *  all orders, using the mean of each context for its Rice parameter,
  *  and use the best.
  *
- * \default \c 0
+ * \default \c 5
  * \param  encoder  An encoder instance to set.
  * \param  value    See above.
  * \assert
@@ -1089,7 +1089,7 @@
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Deprecated.  Setting this value has no effect.
  *
@@ -1101,7 +1101,7 @@
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set an estimate of the total samples that will be encoded.
  *  This is merely an estimate and may be set to \c 0 if unknown.
@@ -1200,7 +1200,7 @@
  *    \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);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t num_blocks);
 
 /** Get the current encoder state.
  *
@@ -1254,7 +1254,7 @@
  * \assert
  *    \code encoder != NULL \endcode
  */
-FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got);
 
 /** Get the "verify" flag.
  *
@@ -1281,40 +1281,40 @@
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_channels().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
 
 /** Get the input sample resolution setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_bits_per_sample().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
 
 /** Get the input sample rate setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_sample_rate().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
 
 /** Get the blocksize setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_blocksize().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
 
 /** Get the "mid/side stereo coding" flag.
  *
@@ -1341,20 +1341,20 @@
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_max_lpc_order().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
 
 /** Get the quantized linear predictor coefficient precision setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_qlp_coeff_precision().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
 
 /** Get the qlp coefficient precision search flag.
  *
@@ -1391,30 +1391,30 @@
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_min_residual_partition_order().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
 
 /** Get maximum residual partition order setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_max_residual_partition_order().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
 
 /** Get the Rice parameter search distance setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_rice_parameter_search_dist().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
 
 /** Get the previously set estimate of the total samples to be encoded.
  *  The encoder merely mimics back the value given to
@@ -1747,7 +1747,7 @@
  *    encoder state with FLAC__stream_encoder_get_state() to see what
  *    went wrong.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples);
 
 /** Submit data for encoding.
  *  This version allows you to supply the input data where the channels
@@ -1779,7 +1779,7 @@
  *    encoder state with FLAC__stream_encoder_get_state() to see what
  *    went wrong.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples);
 
 /* \} */
 
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..ce567b8
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,23 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+if FLaC__WITH_CPPLIBS
+CPPLIBS_DIRS = FLAC++
+endif
+
+SUBDIRS = FLAC $(CPPLIBS_DIRS) share test_libs_common
diff --git a/include/share/Makefile.am b/include/share/Makefile.am
new file mode 100644
index 0000000..079c169
--- /dev/null
+++ b/include/share/Makefile.am
@@ -0,0 +1,19 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = grabbag
+
+EXTRA_DIST = \
+	alloc.h \
+	compat.h \
+	endswap.h \
+	getopt.h \
+	grabbag.h \
+	macros.h \
+	msvc2005_int.h \
+	private.h \
+	replaygain_analysis.h \
+	replaygain_synthesis.h \
+	safe_str.h \
+	utf8.h \
+	win_utf8_io.h \
+	windows_unicode_filenames.h
diff --git a/include/share/compat.h b/include/share/compat.h
index 2083f3a..6d37c97 100644
--- a/include/share/compat.h
+++ b/include/share/compat.h
@@ -29,7 +29,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* This is the prefered location of all CPP hackery to make $random_compiler
+/* This is the preferred location of all CPP hackery to make $random_compiler
  * work like something approaching a C99 (or maybe more accurately GNU99)
  * compiler.
  *
@@ -63,7 +63,6 @@
 #endif
 
 #if HAVE_INTTYPES_H
-#define __STDC_FORMAT_MACROS
 #include <inttypes.h>
 #endif
 
@@ -72,7 +71,7 @@
 #define strtoull _strtoui64
 #endif
 
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__cplusplus)
 #define inline __inline
 #endif
 
@@ -98,7 +97,7 @@
 #define FLAC__STRNCASECMP strncasecmp
 #endif
 
-#if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ || defined __EMX__
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
 #include <io.h> /* for _setmode(), chmod() */
 #include <fcntl.h> /* for _O_BINARY */
 #else
@@ -112,9 +111,13 @@
 #include <sys/utime.h> /* for utime() */
 #endif
 #else
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+#include <fcntl.h>
+#else
 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
 #include <utime.h> /* for utime() */
 #endif
+#endif
 
 #if defined _MSC_VER
 #  if _MSC_VER >= 1800
@@ -130,14 +133,6 @@
 #    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"
@@ -168,11 +163,15 @@
 
 #define flac_fopen fopen
 #define flac_chmod chmod
-#define flac_utime utime
 #define flac_unlink unlink
 #define flac_rename rename
 #define flac_stat stat
 
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+#define flac_utime(a, b) utimensat (AT_FDCWD, a, *b, 0)
+#else
+#define flac_utime utime
+#endif
 #endif
 
 #ifdef _WIN32
@@ -183,6 +182,10 @@
 #define flac_fstat fstat
 #endif
 
+#ifdef ANDROID
+#include <limits.h>
+#endif
+
 #ifndef M_LN2
 #define M_LN2 0.69314718055994530942
 #endif
diff --git a/include/share/grabbag/Makefile.am b/include/share/grabbag/Makefile.am
new file mode 100644
index 0000000..22baa15
--- /dev/null
+++ b/include/share/grabbag/Makefile.am
@@ -0,0 +1,8 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = \
+	cuesheet.h \
+	file.h \
+	picture.h \
+	replaygain.h \
+	seektable.h
diff --git a/include/share/grabbag/cuesheet.h b/include/share/grabbag/cuesheet.h
index b465ae6..1e66925 100644
--- a/include/share/grabbag/cuesheet.h
+++ b/include/share/grabbag/cuesheet.h
@@ -29,10 +29,10 @@
 extern "C" {
 #endif
 
-unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames);
-void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames);
+uint32_t grabbag__cuesheet_msf_to_frame(uint32_t minutes, uint32_t seconds, uint32_t frames);
+void grabbag__cuesheet_frame_to_msf(uint32_t frame, uint32_t *minutes, uint32_t *seconds, uint32_t *frames);
 
-FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, unsigned sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset);
+FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, uint32_t *last_line_read, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset);
 
 void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference);
 
diff --git a/include/share/grabbag/replaygain.h b/include/share/grabbag/replaygain.h
index faa3272..fdf63ac 100644
--- a/include/share/grabbag/replaygain.h
+++ b/include/share/grabbag/replaygain.h
@@ -34,7 +34,7 @@
 extern "C" {
 #endif
 
-extern const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
+extern const uint32_t GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
 
 extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS; /* = "REPLAYGAIN_REFERENCE_LOUDNESS" */
 extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN; /* = "REPLAYGAIN_TRACK_GAIN" */
@@ -42,12 +42,12 @@
 extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN; /* = "REPLAYGAIN_ALBUM_GAIN" */
 extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK; /* = "REPLAYGAIN_ALBUM_PEAK" */
 
-FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency);
+FLAC__bool grabbag__replaygain_is_valid_sample_frequency(uint32_t sample_frequency);
 
-FLAC__bool grabbag__replaygain_init(unsigned sample_frequency);
+FLAC__bool grabbag__replaygain_init(uint32_t sample_frequency);
 
 /* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */
-FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples);
+FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, uint32_t bps, uint32_t samples);
 
 void grabbag__replaygain_get_album(float *gain, float *peak);
 void grabbag__replaygain_get_title(float *gain, float *peak);
diff --git a/include/share/grabbag/seektable.h b/include/share/grabbag/seektable.h
index ac294a3..191a1c4 100644
--- a/include/share/grabbag/seektable.h
+++ b/include/share/grabbag/seektable.h
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points);
+FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, uint32_t sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points);
 
 #ifdef __cplusplus
 }
diff --git a/include/share/msvc2005_int.h b/include/share/msvc2005_int.h
new file mode 100644
index 0000000..f789fb1
--- /dev/null
+++ b/include/share/msvc2005_int.h
@@ -0,0 +1,53 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2017  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 header file defines integer [u]intNN_t types.
+ * It is auto-included in all files via "Force Includes" (/FI)
+ * option in all *.vcproj files (Visual Studio 2005, 2008)
+ */
+
+#ifndef FLAC__SHARE__MSVC2005_INT_H
+#define FLAC__SHARE__MSVC2005_INT_H
+
+#if defined _MSC_VER && _MSC_VER < 1600
+
+typedef signed __int8 int8_t;
+typedef signed __int16 int16_t;
+typedef signed __int32 int32_t;
+typedef signed __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#endif
+
+#endif /* FLAC__SHARE__MSVC2005_INT_H */
diff --git a/include/share/private.h b/include/share/private.h
index f7e3b85..03083d3 100644
--- a/include/share/private.h
+++ b/include/share/private.h
@@ -33,7 +33,7 @@
 #define FLAC__SHARE__PRIVATE_H
 
 /*
- * Unpublished debug routines from libFLAC> This should not be used from any
+ * 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);
diff --git a/include/share/replaygain_synthesis.h b/include/share/replaygain_synthesis.h
index 5f4c3ff..9bec5e5 100644
--- a/include/share/replaygain_synthesis.h
+++ b/include/share/replaygain_synthesis.h
@@ -47,6 +47,6 @@
 void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype);
 
 /* scale = (float) pow(10., (double)replaygain * 0.05); */
-size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context);
+size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, const uint32_t source_bps, const uint32_t target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context);
 
 #endif
diff --git a/include/share/safe_str.h b/include/share/safe_str.h
index eb974c5..6709334 100644
--- a/include/share/safe_str.h
+++ b/include/share/safe_str.h
@@ -46,7 +46,9 @@
 	if (dest_size < 1)
 		return dest;
 
+	/* Assume dist has space for a term character .. */
 	ret = strncat(dest, src, dest_size - strlen (dest));
+	/* .. but set it explicitly. */
 	dest [dest_size - 1] = 0;
 
 	return ret;
@@ -60,7 +62,7 @@
 	if (dest_size < 1)
 		return dest;
 
-	ret = strncpy(dest, src, dest_size);
+	ret = strncpy(dest, src, dest_size - 1);
 	dest [dest_size - 1] = 0;
 
 	return ret;
diff --git a/include/share/win_utf8_io.h b/include/share/win_utf8_io.h
index 13fd118..6031b89 100644
--- a/include/share/win_utf8_io.h
+++ b/include/share/win_utf8_io.h
@@ -50,6 +50,9 @@
 int fprintf_utf8(FILE *stream, const char *format, ...);
 int vfprintf_utf8(FILE *stream, const char *format, va_list argptr);
 
+#include <windows.h>
+HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/include/share/windows_unicode_filenames.h b/include/share/windows_unicode_filenames.h
index 86820ca..94cbeb6 100644
--- a/include/share/windows_unicode_filenames.h
+++ b/include/share/windows_unicode_filenames.h
@@ -39,25 +39,24 @@
 #include <sys/utime.h>
 #include "FLAC/ordinals.h"
 
+/***** FIXME: KLUDGE: export these syms for flac.exe, metaflac.exe, etc. *****/
+#include "FLAC/export.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-void flac_internal_set_utf8_filenames(FLAC__bool flag);
-FLAC__bool flac_internal_get_utf8_filenames(void);
+FLAC_API void flac_internal_set_utf8_filenames(FLAC__bool flag);
+FLAC_API FLAC__bool flac_internal_get_utf8_filenames(void);
 #define flac_set_utf8_filenames flac_internal_set_utf8_filenames
 #define flac_get_utf8_filenames flac_internal_get_utf8_filenames
 
-FILE* flac_internal_fopen_utf8(const char *filename, const char *mode);
-int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer);
-int flac_internal_chmod_utf8(const char *filename, int pmode);
-int flac_internal_utime_utf8(const char *filename, struct utimbuf *times);
-int flac_internal_unlink_utf8(const char *filename);
-int flac_internal_rename_utf8(const char *oldname, const char *newname);
-
-#include <windows.h>
-HANDLE WINAPI flac_internal_CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
-#define CreateFile_utf8 flac_internal_CreateFile_utf8
+FLAC_API FILE* flac_internal_fopen_utf8(const char *filename, const char *mode);
+FLAC_API int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer);
+FLAC_API int flac_internal_chmod_utf8(const char *filename, int pmode);
+FLAC_API int flac_internal_utime_utf8(const char *filename, struct utimbuf *times);
+FLAC_API int flac_internal_unlink_utf8(const char *filename);
+FLAC_API int flac_internal_rename_utf8(const char *oldname, const char *newname);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/include/test_libs_common/Makefile.am b/include/test_libs_common/Makefile.am
new file mode 100644
index 0000000..af82b4d
--- /dev/null
+++ b/include/test_libs_common/Makefile.am
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = \
+	file_utils_flac.h \
+	metadata_utils.h
diff --git a/include/test_libs_common/file_utils_flac.h b/include/test_libs_common/file_utils_flac.h
new file mode 100644
index 0000000..7687c8f
--- /dev/null
+++ b/include/test_libs_common/file_utils_flac.h
@@ -0,0 +1,36 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_FILE_UTILS_H
+#define FLAC__TEST_LIBFLAC_FILE_UTILS_H
+
+/* needed because of off_t */
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/format.h"
+#include <sys/types.h> /* for off_t */
+#include "share/compat.h"
+
+extern const long file_utils__ogg_serial_number;
+
+FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, FLAC__off_t *output_filesize, uint32_t length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, uint32_t num_metadata);
+
+#endif
diff --git a/include/test_libs_common/metadata_utils.h b/include/test_libs_common/metadata_utils.h
new file mode 100644
index 0000000..6bd4e8f
--- /dev/null
+++ b/include/test_libs_common/metadata_utils.h
@@ -0,0 +1,71 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBS_COMMON_METADATA_UTILS_H
+#define FLAC__TEST_LIBS_COMMON_METADATA_UTILS_H
+
+/*
+ * These are not tests, just utility functions used by the metadata tests
+ */
+
+#include "FLAC/format.h"
+
+FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy);
+
+FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, uint32_t block_length);
+
+FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, uint32_t block_length);
+
+FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy);
+
+FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy);
+
+FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy);
+
+FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy);
+
+FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, uint32_t block_length);
+
+FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy);
+
+void mutils__init_metadata_blocks(
+	FLAC__StreamMetadata *streaminfo,
+	FLAC__StreamMetadata *padding,
+	FLAC__StreamMetadata *seektable,
+	FLAC__StreamMetadata *application1,
+	FLAC__StreamMetadata *application2,
+	FLAC__StreamMetadata *vorbiscomment,
+	FLAC__StreamMetadata *cuesheet,
+	FLAC__StreamMetadata *picture,
+	FLAC__StreamMetadata *unknown
+);
+
+void mutils__free_metadata_blocks(
+	FLAC__StreamMetadata *streaminfo,
+	FLAC__StreamMetadata *padding,
+	FLAC__StreamMetadata *seektable,
+	FLAC__StreamMetadata *application1,
+	FLAC__StreamMetadata *application2,
+	FLAC__StreamMetadata *vorbiscomment,
+	FLAC__StreamMetadata *cuesheet,
+	FLAC__StreamMetadata *picture,
+	FLAC__StreamMetadata *unknown
+);
+
+#endif
diff --git a/libFLAC/Android.bp b/libFLAC/Android.bp
deleted file mode 100644
index 4376ee2..0000000
--- a/libFLAC/Android.bp
+++ /dev/null
@@ -1,62 +0,0 @@
-cc_library_static {
-    name: "libFLAC",
-    vendor_available: true,
-
-    srcs: [
-        "bitmath.c",
-        "bitreader.c",
-        "bitwriter.c",
-        "cpu.c",
-        "crc.c",
-        "fixed.c",
-        "float.c",
-        "format.c",
-        "lpc.c",
-        "memory.c",
-        "md5.c",
-        "stream_decoder.c",
-        "stream_encoder.c",
-        "stream_encoder_framing.c",
-        "window.c",
-    ],
-
-    local_include_dirs: ["include"],
-    header_libs: [
-        "libFLAC-config",
-        "libFLAC-headers",
-    ],
-    export_header_lib_headers: ["libFLAC-headers"],
-
-    cflags: [
-        "-DHAVE_CONFIG_H",
-        "-DFLAC__NO_MD5",
-        "-DFLAC__INTEGER_ONLY_LIBRARY",
-
-        "-D_REENTRANT",
-        "-DPIC",
-        "-DU_COMMON_IMPLEMENTATION",
-        "-fPIC",
-
-        "-O3",
-        "-funroll-loops",
-        "-finline-functions",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
-
-    arch: {
-        arm: {
-            instruction_set: "arm",
-        },
-    },
-
-    sanitize: {
-        integer_overflow: true,
-        misc_undefined: ["bounds"],
-        // Enable CFI if this is used as a shared library
-        // cfi: true,
-        blacklist: "libFLAC_blacklist.txt",
-    },
-
-    min_sdk_version: "29",
-}
diff --git a/libFLAC/bitmath.c b/libFLAC/bitmath.c
deleted file mode 100644
index b3d797d..0000000
--- a/libFLAC/bitmath.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/bitmath.h"
-
-/* An example of what FLAC__bitmath_silog2() computes:
- *
- * silog2(-10) = 5
- * silog2(- 9) = 5
- * silog2(- 8) = 4
- * silog2(- 7) = 4
- * silog2(- 6) = 4
- * silog2(- 5) = 4
- * silog2(- 4) = 3
- * silog2(- 3) = 3
- * silog2(- 2) = 2
- * silog2(- 1) = 2
- * silog2(  0) = 0
- * silog2(  1) = 2
- * silog2(  2) = 3
- * silog2(  3) = 3
- * silog2(  4) = 4
- * silog2(  5) = 4
- * silog2(  6) = 4
- * silog2(  7) = 4
- * silog2(  8) = 5
- * silog2(  9) = 5
- * silog2( 10) = 5
- */
-unsigned FLAC__bitmath_silog2(FLAC__int64 v)
-{
-	if(v == 0)
-		return 0;
-
-	if(v == -1)
-		return 2;
-
-	v = (v < 0) ? (-(v+1)) : v;
-	return FLAC__bitmath_ilog2_wide(v)+2;
-}
diff --git a/libFLAC/bitreader.c b/libFLAC/bitreader.c
deleted file mode 100644
index ab62d41..0000000
--- a/libFLAC/bitreader.c
+++ /dev/null
@@ -1,1087 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 COUNT_ZERO_MSBS2 below to match */
-/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */
-/*           also, some sections currently only have fast versions for 4 or 8 bytes per word */
-
-#if (ENABLE_64_BIT_WORDS == 0)
-
-typedef FLAC__uint32 brword;
-#define FLAC__BYTES_PER_WORD 4		/* sizeof brword */
-#define FLAC__BITS_PER_WORD 32
-#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
-/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (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
-/* counts the # of zero MSBs in a word */
-#define COUNT_ZERO_MSBS(word) FLAC__clz_uint32(word)
-#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint32(word)
-
-#else
-
-typedef FLAC__uint64 brword;
-#define FLAC__BYTES_PER_WORD 8		/* sizeof brword */
-#define FLAC__BITS_PER_WORD 64
-#define FLAC__WORD_ALL_ONES ((FLAC__uint64)FLAC__U64L(0xffffffffffffffff))
-/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (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_64(x)
-#endif
-/* counts the # of zero MSBs in a word */
-#define COUNT_ZERO_MSBS(word) FLAC__clz_uint64(word)
-#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint64(word)
-
-#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 */
-	brword *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, brword 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 brword 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 + (unsigned)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 + (unsigned)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(brword) * 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] & ((brword)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] & ((brword)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 brword 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 brword word = br->buffer[br->consumed_words];
-			if(bits < n) {
-				*val = (FLAC__uint32)((word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (n-bits)); /* The result has <= 32 non-zero bits */
-				br->consumed_bits += bits;
-				return true;
-			}
-			/* (FLAC__BITS_PER_WORD - br->consumed_bits <= bits) ==> (FLAC__WORD_ALL_ONES >> br->consumed_bits) has no more than 'bits' non-zero bits */
-			*val = (FLAC__uint32)(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 |= (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits));
-				br->consumed_bits = bits;
-			}
-			return true;
-		}
-		else { /* br->consumed_bits == 0 */
-			const brword word = br->buffer[br->consumed_words];
-			if(bits < FLAC__BITS_PER_WORD) {
-				*val = (FLAC__uint32)(word >> (FLAC__BITS_PER_WORD-bits));
-				br->consumed_bits = bits;
-				return true;
-			}
-			/* at this point bits == FLAC__BITS_PER_WORD == 32; because of previous assertions, it can't be larger */
-			*val = (FLAC__uint32)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 = (FLAC__uint32)((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 = (FLAC__uint32)(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)
-{
-	FLAC__uint32 uval, mask;
-	/* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */
-	if(!FLAC__bitreader_read_raw_uint32(br, &uval, bits))
-		return false;
-	/* sign-extend *val assuming it is currently bits wide. */
-	/* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */
-	mask = 1u << (bits - 1);
-	*val = (uval ^ mask) - mask;
-	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 brword 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... */
-			brword b = br->buffer[br->consumed_words] << br->consumed_bits;
-			if(b) {
-				i = COUNT_ZERO_MSBS(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;
-			brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits;
-			if(b) {
-				i = COUNT_ZERO_MSBS(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 */
-	brword 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 = COUNT_ZERO_MSBS2(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 = COUNT_ZERO_MSBS2(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 = (FLAC__uint32)(b >> (FLAC__BITS_PER_WORD - parameter)); /* parameter < 32, so we can cast to 32-bit unsigned */
-		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 |= (FLAC__uint32)(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);
diff --git a/libFLAC/bitwriter.c b/libFLAC/bitwriter.c
deleted file mode 100644
index 402b1c4..0000000
--- a/libFLAC/bitwriter.c
+++ /dev/null
@@ -1,881 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 bwword is >= 32 bits wide */
-
-#if (ENABLE_64_BIT_WORDS == 0)
-
-typedef FLAC__uint32 bwword;
-#define FLAC__BYTES_PER_WORD 4		/* sizeof bwword */
-#define FLAC__BITS_PER_WORD 32
-/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (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
-
-#else
-
-typedef FLAC__uint64 bwword;
-#define FLAC__BYTES_PER_WORD 8		/* sizeof bwword */
-#define FLAC__BITS_PER_WORD 64
-/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (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_64(x)
-#endif
-
-#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(bwword); /* size in words */
-/* When growing, increment 4K at a time */
-static const unsigned FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(bwword); /* 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 {
-	bwword *buffer;
-	bwword 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;
-	bwword *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(bwword), /*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(bwword) * 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] & ((bwword)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 & ((bwword)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;
-}
-
-static inline FLAC__bool FLAC__bitwriter_write_raw_uint32_nocheck(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);
-
-	if(bw == 0 || bw->buffer == 0)
-		return false;
-
-	if (bits > 32)
-		return false;
-
-	if(bits == 0)
-		return true;
-
-	FLAC__ASSERT((bits == 32) || (val>>bits == 0));
-
-	/* 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; /* unused top bits can contain garbage */
-	}
-	else { /* at this point bits == FLAC__BITS_PER_WORD == 32  and  bw->bits == 0 */
-		bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST((bwword)val);
-	}
-
-	return true;
-}
-
-inline FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits)
-{
-	/* check that unused bits are unset */
-	if((bits < 32) && (val>>bits != 0))
-		return false;
-
-	return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, bits);
-}
-
-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_nocheck(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_nocheck(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_nocheck(bw, val & 0xff, 8))
-		return false;
-	if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>8) & 0xff, 8))
-		return false;
-	if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>16) & 0xff, 8))
-		return false;
-	if(!FLAC__bitwriter_write_raw_uint32_nocheck(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_nocheck(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_nocheck(bw, 1, ++val);
-	else
-		return
-			FLAC__bitwriter_write_zeroes(bw, val) &&
-			FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, 1);
-}
-
-unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter)
-{
-	FLAC__uint32 uval;
-
-	FLAC__ASSERT(parameter < 32);
-
-	/* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
-	uval = val;
-	uval <<= 1;
-	uval ^= (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 < 32);
-
-	/* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
-	uval = val;
-	uval <<= 1;
-	uval ^= (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__uint32)0xffffffff << parameter; /* we val|=mask1 to set the stop bit above it... */
-	const FLAC__uint32 mask2 = (FLAC__uint32)0xffffffff >> (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, total_bits;
-
-	FLAC__ASSERT(0 != bw);
-	FLAC__ASSERT(0 != bw->buffer);
-	FLAC__ASSERT(parameter < 31);
-	/* 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;
-		uval <<= 1;
-		uval ^= (*vals>>31);
-
-		msbits = uval >> parameter;
-		total_bits = lsbits + msbits;
-
-		if(bw->bits && bw->bits + total_bits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */
-			/* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */
-			bw->bits += total_bits;
-			uval |= mask1; /* set stop bit */
-			uval &= mask2; /* mask off unused top bits */
-			bw->accum <<= total_bits;
-			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 bwword */ && !bitwriter_grow_(bw, total_bits))
-				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; /* unused top bits can contain garbage */
-			}
-		}
-		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);
-
-	if((val & 0x80000000) != 0) /* this version only handles 31 bits */
-		return false;
-
-	if(val < 0x80) {
-		return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, 8);
-	}
-	else if(val < 0x800) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (val>>6), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
-	}
-	else if(val < 0x10000) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (val>>12), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
-	}
-	else if(val < 0x200000) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (val>>18), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
-	}
-	else if(val < 0x4000000) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (val>>24), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
-	}
-	else {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (val>>30), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>24)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(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);
-
-	if((val & FLAC__U64L(0xFFFFFFF000000000)) != 0) /* this version only handles 36 bits */
-		return false;
-
-	if(val < 0x80) {
-		return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, 8);
-	}
-	else if(val < 0x800) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (FLAC__uint32)(val>>6), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
-	}
-	else if(val < 0x10000) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (FLAC__uint32)(val>>12), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
-	}
-	else if(val < 0x200000) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (FLAC__uint32)(val>>18), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
-	}
-	else if(val < 0x4000000) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (FLAC__uint32)(val>>24), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
-	}
-	else if(val < 0x80000000) {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (FLAC__uint32)(val>>30), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
-	}
-	else {
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFE, 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
-		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(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_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, 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);
diff --git a/libFLAC/cpu.c b/libFLAC/cpu.c
deleted file mode 100644
index b9df19a..0000000
--- a/libFLAC/cpu.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-#include "share/compat.h"
-#include <stdlib.h>
-#include <memory.h>
-
-#if defined(_MSC_VER)
-#  include <intrin.h> /* for __cpuid() and _xgetbv() */
-#endif
-
-#if defined __GNUC__ && defined HAVE_CPUID_H
-#  include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
-#endif
-
-#ifdef DEBUG
-#include <stdio.h>
-
-#define dfprintf fprintf
-#else
-/* This is bad practice, it should be a static void empty function */
-#define dfprintf(file, format, ...)
-#endif
-
-
-#if defined 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_SSE = 0x02000000;
-static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
-#endif
-
-#if FLAC__HAS_X86INTRIN || FLAC__AVX_SUPPORTED
-/* 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;
-
-/* 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
-
-#if defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64
-static uint32_t
-cpu_xgetbv_x86(void)
-{
-#if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__HAS_X86INTRIN && FLAC__AVX_SUPPORTED
-	return (uint32_t)_xgetbv(0);
-#elif defined __GNUC__
-	uint32_t lo, hi;
-	asm volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
-	return lo;
-#else
-	return 0;
-#endif
-}
-#endif
-
-static void
-ia32_cpu_info (FLAC__CPUInfo *info)
-{
-#if !defined FLAC__CPU_IA32
-	(void) info;
-#else
-	FLAC__bool ia32_osxsave = false;
-	FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
-
-#if !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN)
-	info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
-#if defined FLAC__HAS_NASM
-	if(!FLAC__cpu_have_cpuid_asm_ia32())
-		return;
-#endif
-	/* http://www.sandpile.org/x86/cpuid.htm */
-	if (FLAC__HAS_X86INTRIN) {
-		FLAC__cpu_info_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
-		info->ia32.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
-		FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
-	}
-	else {
-		FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
-	}
-
-	info->ia32.cmov  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV ) ? true : false;
-	info->ia32.mmx   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX  ) ? 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 (FLAC__HAS_X86INTRIN && 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;
-	}
-
-	dfprintf(stderr, "CPU info (IA-32):\n");
-	dfprintf(stderr, "  CMOV ....... %c\n", info->ia32.cmov    ? 'Y' : 'n');
-	dfprintf(stderr, "  MMX ........ %c\n", info->ia32.mmx     ? 'Y' : 'n');
-	dfprintf(stderr, "  SSE ........ %c\n", info->ia32.sse     ? 'Y' : 'n');
-	dfprintf(stderr, "  SSE2 ....... %c\n", info->ia32.sse2    ? 'Y' : 'n');
-	dfprintf(stderr, "  SSE3 ....... %c\n", info->ia32.sse3    ? 'Y' : 'n');
-	dfprintf(stderr, "  SSSE3 ...... %c\n", info->ia32.ssse3   ? 'Y' : 'n');
-	dfprintf(stderr, "  SSE41 ...... %c\n", info->ia32.sse41   ? 'Y' : 'n');
-	dfprintf(stderr, "  SSE42 ...... %c\n", info->ia32.sse42   ? 'Y' : 'n');
-
-	if (FLAC__HAS_X86INTRIN && FLAC__AVX_SUPPORTED) {
-		dfprintf(stderr, "  AVX ........ %c\n", info->ia32.avx     ? 'Y' : 'n');
-		dfprintf(stderr, "  FMA ........ %c\n", info->ia32.fma     ? 'Y' : 'n');
-		dfprintf(stderr, "  AVX2 ....... %c\n", info->ia32.avx2    ? 'Y' : 'n');
-	}
-
-	/*
-	 * now have to check for OS support of AVX instructions
-	 */
-	if (!FLAC__HAS_X86INTRIN || !info->ia32.avx || !ia32_osxsave || (cpu_xgetbv_x86() & 0x6) != 0x6) {
-		/* no OS AVX support */
-		info->ia32.avx     = false;
-		info->ia32.avx2    = false;
-		info->ia32.fma     = false;
-	}
-
-	if (FLAC__HAS_X86INTRIN && FLAC__AVX_SUPPORTED) {
-		dfprintf(stderr, "  AVX OS sup . %c\n", info->ia32.avx ? 'Y' : 'n');
-	}
-#else
-	info->use_asm = false;
-#endif
-#endif
-}
-
-static void
-x86_64_cpu_info (FLAC__CPUInfo *info)
-{
-#if !defined FLAC__NO_ASM && FLAC__HAS_X86INTRIN
-	FLAC__bool x86_osxsave = false;
-	FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
-
-	info->use_asm = true;
-
-	/* http://www.sandpile.org/x86/cpuid.htm */
-	FLAC__cpu_info_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
-	info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
-	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 (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;
-	}
-
-	dfprintf(stderr, "CPU info (x86-64):\n");
-	dfprintf(stderr, "  SSE3 ....... %c\n", info->x86.sse3  ? 'Y' : 'n');
-	dfprintf(stderr, "  SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n');
-	dfprintf(stderr, "  SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n');
-	dfprintf(stderr, "  SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n');
-
-	if (FLAC__AVX_SUPPORTED) {
-		dfprintf(stderr, "  AVX ........ %c\n", info->x86.avx   ? 'Y' : 'n');
-		dfprintf(stderr, "  FMA ........ %c\n", info->x86.fma   ? 'Y' : 'n');
-		dfprintf(stderr, "  AVX2 ....... %c\n", info->x86.avx2  ? 'Y' : 'n');
-	}
-
-	/*
-	 * now have to check for OS support of AVX instructions
-	 */
-	if (!info->x86.avx || !x86_osxsave || (cpu_xgetbv_x86() & 0x6) != 0x6) {
-		/* no OS AVX support */
-		info->x86.avx     = false;
-		info->x86.avx2    = false;
-		info->x86.fma     = false;
-	}
-
-	if (FLAC__AVX_SUPPORTED) {
-		dfprintf(stderr, "  AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
-	}
-#else
-	/* Silence compiler warnings. */
-	(void) info;
-#if defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64
-	if (0) cpu_xgetbv_x86 ();
-#endif
-#endif
-}
-
-void FLAC__cpu_info (FLAC__CPUInfo *info)
-{
-	memset(info, 0, sizeof(*info));
-
-#ifdef FLAC__CPU_IA32
-	info->type = FLAC__CPUINFO_TYPE_IA32;
-#elif defined FLAC__CPU_X86_64
-	info->type = FLAC__CPUINFO_TYPE_X86_64;
-#else
-	info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
-	info->use_asm = false;
-#endif
-
-	switch (info->type) {
-	case FLAC__CPUINFO_TYPE_IA32:
-		ia32_cpu_info (info);
-		break;
-	case FLAC__CPUINFO_TYPE_X86_64:
-		x86_64_cpu_info (info);
-		break;
-	default:
-		info->use_asm = false;
-		break;
-	}
-}
-
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-
-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) {
-#if FLAC__AVX_SUPPORTED
-		__cpuidex(cpuinfo, ext, 0); /* for AVX2 detection */
-#else
-		__cpuid(cpuinfo, ext); /* some old compilers don't support __cpuidex */
-#endif
-
-		*eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
-
-		return;
-	}
-#elif defined __GNUC__ && defined HAVE_CPUID_H
-	FLAC__uint32 ext = level & 0x80000000;
-	__cpuid(ext, *eax, *ebx, *ecx, *edx);
-	if (*eax >= level) {
-		__cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
-
-		return;
-	}
-#endif
-	*eax = *ebx = *ecx = *edx = 0;
-}
-
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
diff --git a/libFLAC/crc.c b/libFLAC/crc.c
deleted file mode 100644
index 8123c3b..0000000
--- a/libFLAC/crc.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/crc.h"
-
-/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
-
-FLAC__byte const FLAC__crc8_table[256] = {
-	0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
-	0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
-	0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
-	0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
-	0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
-	0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
-	0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
-	0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
-	0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
-	0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
-	0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
-	0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
-	0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
-	0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
-	0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
-	0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
-	0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
-	0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
-	0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
-	0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
-	0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
-	0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
-	0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
-	0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
-	0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
-	0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
-	0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
-	0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
-	0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
-	0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
-	0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
-	0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
-};
-
-/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
-
-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,
-	0x0050,  0x8055,  0x805f,  0x005a,  0x804b,  0x004e,  0x0044,  0x8041,
-	0x80c3,  0x00c6,  0x00cc,  0x80c9,  0x00d8,  0x80dd,  0x80d7,  0x00d2,
-	0x00f0,  0x80f5,  0x80ff,  0x00fa,  0x80eb,  0x00ee,  0x00e4,  0x80e1,
-	0x00a0,  0x80a5,  0x80af,  0x00aa,  0x80bb,  0x00be,  0x00b4,  0x80b1,
-	0x8093,  0x0096,  0x009c,  0x8099,  0x0088,  0x808d,  0x8087,  0x0082,
-	0x8183,  0x0186,  0x018c,  0x8189,  0x0198,  0x819d,  0x8197,  0x0192,
-	0x01b0,  0x81b5,  0x81bf,  0x01ba,  0x81ab,  0x01ae,  0x01a4,  0x81a1,
-	0x01e0,  0x81e5,  0x81ef,  0x01ea,  0x81fb,  0x01fe,  0x01f4,  0x81f1,
-	0x81d3,  0x01d6,  0x01dc,  0x81d9,  0x01c8,  0x81cd,  0x81c7,  0x01c2,
-	0x0140,  0x8145,  0x814f,  0x014a,  0x815b,  0x015e,  0x0154,  0x8151,
-	0x8173,  0x0176,  0x017c,  0x8179,  0x0168,  0x816d,  0x8167,  0x0162,
-	0x8123,  0x0126,  0x012c,  0x8129,  0x0138,  0x813d,  0x8137,  0x0132,
-	0x0110,  0x8115,  0x811f,  0x011a,  0x810b,  0x010e,  0x0104,  0x8101,
-	0x8303,  0x0306,  0x030c,  0x8309,  0x0318,  0x831d,  0x8317,  0x0312,
-	0x0330,  0x8335,  0x833f,  0x033a,  0x832b,  0x032e,  0x0324,  0x8321,
-	0x0360,  0x8365,  0x836f,  0x036a,  0x837b,  0x037e,  0x0374,  0x8371,
-	0x8353,  0x0356,  0x035c,  0x8359,  0x0348,  0x834d,  0x8347,  0x0342,
-	0x03c0,  0x83c5,  0x83cf,  0x03ca,  0x83db,  0x03de,  0x03d4,  0x83d1,
-	0x83f3,  0x03f6,  0x03fc,  0x83f9,  0x03e8,  0x83ed,  0x83e7,  0x03e2,
-	0x83a3,  0x03a6,  0x03ac,  0x83a9,  0x03b8,  0x83bd,  0x83b7,  0x03b2,
-	0x0390,  0x8395,  0x839f,  0x039a,  0x838b,  0x038e,  0x0384,  0x8381,
-	0x0280,  0x8285,  0x828f,  0x028a,  0x829b,  0x029e,  0x0294,  0x8291,
-	0x82b3,  0x02b6,  0x02bc,  0x82b9,  0x02a8,  0x82ad,  0x82a7,  0x02a2,
-	0x82e3,  0x02e6,  0x02ec,  0x82e9,  0x02f8,  0x82fd,  0x82f7,  0x02f2,
-	0x02d0,  0x82d5,  0x82df,  0x02da,  0x82cb,  0x02ce,  0x02c4,  0x82c1,
-	0x8243,  0x0246,  0x024c,  0x8249,  0x0258,  0x825d,  0x8257,  0x0252,
-	0x0270,  0x8275,  0x827f,  0x027a,  0x826b,  0x026e,  0x0264,  0x8261,
-	0x0220,  0x8225,  0x822f,  0x022a,  0x823b,  0x023e,  0x0234,  0x8231,
-	0x8213,  0x0216,  0x021c,  0x8219,  0x0208,  0x820d,  0x8207,  0x0202
-};
-
-
-void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc)
-{
-	*crc = FLAC__crc8_table[*crc ^ data];
-}
-
-void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc)
-{
-	while(len--)
-		*crc = FLAC__crc8_table[*crc ^ *data++];
-}
-
-FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len)
-{
-	FLAC__uint8 crc = 0;
-
-	while(len--)
-		crc = FLAC__crc8_table[crc ^ *data++];
-
-	return crc;
-}
-
-unsigned FLAC__crc16(const FLAC__byte *data, unsigned len)
-{
-	unsigned crc = 0;
-
-	while(len--)
-		crc = ((crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]) & 0xffff;
-
-	return crc;
-}
diff --git a/libFLAC/fixed.c b/libFLAC/fixed.c
deleted file mode 100644
index 2e16251..0000000
--- a/libFLAC/fixed.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 <string.h>
-#include "share/compat.h"
-#include "private/bitmath.h"
-#include "private/fixed.h"
-#include "private/macros.h"
-#include "FLAC/assert.h"
-
-#ifdef local_abs
-#undef local_abs
-#endif
-#define local_abs(x) ((unsigned)((x)<0? -(x) : (x)))
-
-#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 -= (int)(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 -= (int)(bits-16); // defined, but cast to int to avoid ubsan assert.
-	}
-	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, 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]);
-	FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
-	FLAC__int32 error, save;
-	FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
-	unsigned i, order;
-
-	for(i = 0; i < data_len; i++) {
-		error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
-		error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
-		error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
-		error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
-		error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
-	}
-
-	if(total_error_0 < 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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
-		order = 1;
-	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;
-	else
-		order = 4;
-
-	/* Estimate the expected number of bits per residual signal sample. */
-	/* 'total_error*' is linearly related to the variance of the residual */
-	/* signal, so we use it directly to compute E(|x|) */
-	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (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;
-}
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, 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];
-	FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
-	FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
-	FLAC__int32 error, save;
-	/* total_error_* are 64-bits to avoid overflow when encoding
-	 * erratic signals when the bits-per-sample and blocksize are
-	 * large.
-	 */
-	FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
-	unsigned i, order;
-
-	for(i = 0; i < data_len; i++) {
-		error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
-		error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
-		error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
-		error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
-		error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
-	}
-
-	if(total_error_0 < 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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
-		order = 1;
-	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;
-	else
-		order = 4;
-
-	/* Estimate the expected number of bits per residual signal sample. */
-	/* 'total_error*' is linearly related to the variance of the residual */
-	/* signal, so we use it directly to compute E(|x|) */
-	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
-#else
-	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;
-}
-
-void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[])
-{
-	const int idata_len = (int)data_len;
-	int i;
-
-	switch(order) {
-		case 0:
-			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++)
-				residual[i] = data[i] - data[i-1];
-			break;
-		case 2:
-			for(i = 0; i < idata_len; i++)
-				residual[i] = data[i] - 2*data[i-1] + data[i-2];
-			break;
-		case 3:
-			for(i = 0; i < idata_len; i++)
-				residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
-			break;
-		case 4:
-			for(i = 0; i < idata_len; i++)
-				residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
-			break;
-		default:
-			FLAC__ASSERT(0);
-	}
-}
-
-void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[])
-{
-	int i, idata_len = (int)data_len;
-
-	switch(order) {
-		case 0:
-			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++)
-				data[i] = residual[i] + data[i-1];
-			break;
-		case 2:
-			for(i = 0; i < idata_len; i++)
-				data[i] = residual[i] + 2*data[i-1] - data[i-2];
-			break;
-		case 3:
-			for(i = 0; i < idata_len; i++)
-				data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
-			break;
-		case 4:
-			for(i = 0; i < idata_len; i++)
-				data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
-			break;
-		default:
-			FLAC__ASSERT(0);
-	}
-}
diff --git a/libFLAC/fixed_intrin_sse2.c b/libFLAC/fixed_intrin_sse2.c
deleted file mode 100644
index 6a9b4dd..0000000
--- a/libFLAC/fixed_intrin_sse2.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
-#include "private/fixed.h"
-#ifdef FLAC__SSE2_SUPPORTED
-
-#include <emmintrin.h> /* SSE2 */
-#include <math.h>
-#include "private/macros.h"
-#include "share/compat.h"
-#include "FLAC/assert.h"
-
-#ifdef FLAC__CPU_IA32
-#define m128i_to_i64(dest, src) _mm_storel_epi64((__m128i*)&dest, src)
-#else
-#define m128i_to_i64(dest, src) dest = _mm_cvtsi128_si64(src)
-#endif
-
-FLAC__SSE_TARGET("sse2")
-unsigned FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], unsigned data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
-{
-	FLAC__uint32 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
-	unsigned i, order;
-
-	__m128i total_err0, total_err1, total_err2;
-
-	{
-		FLAC__int32 itmp;
-		__m128i last_error;
-
-		last_error = _mm_cvtsi32_si128(data[-1]);							// 0   0   0   le0
-		itmp = data[-2];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   0   le0 le1
-		itmp -= data[-3];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   le0 le1 le2
-		itmp -= data[-3] - data[-4];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// le0 le1 le2 le3
-
-		total_err0 = total_err1 = _mm_setzero_si128();
-		for(i = 0; i < data_len; i++) {
-			__m128i err0, err1, tmp;
-			err0 = _mm_cvtsi32_si128(data[i]);								// 0   0   0   e0
-			err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(0,0,0,0));			// e0  e0  e0  e0
-#if 1 /* OPT_SSE */
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   le0 le1 le2
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   0   le0 le1
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   0   0   le0
-			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
-#else
-			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 8));	// le0  le1  le2+le0  le3+le1
-			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 4));	// le0  le1+le0  le2+le0+le1  le3+le1+le2+le0
-			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
-#endif
-			tmp = _mm_slli_si128(err0, 12);									// e0   0   0   0
-			last_error = _mm_srli_si128(err1, 4);							//  0  e1  e2  e3
-			last_error = _mm_or_si128(last_error, tmp);						// e0  e1  e2  e3
-
-			tmp = _mm_srai_epi32(err0, 31);
-			err0 = _mm_xor_si128(err0, tmp);
-			err0 = _mm_sub_epi32(err0, tmp);
-			tmp = _mm_srai_epi32(err1, 31);
-			err1 = _mm_xor_si128(err1, tmp);
-			err1 = _mm_sub_epi32(err1, tmp);
-
-			total_err0 = _mm_add_epi32(total_err0, err0);					// 0   0   0   te0
-			total_err1 = _mm_add_epi32(total_err1, err1);					// te1 te2 te3 te4
-		}
-	}
-
-	total_error_0 = _mm_cvtsi128_si32(total_err0);
-	total_err2 = total_err1;											// te1  te2  te3  te4
-	total_err1 = _mm_srli_si128(total_err1, 8);							//  0    0   te1  te2
-	total_error_4 = _mm_cvtsi128_si32(total_err2);
-	total_error_2 = _mm_cvtsi128_si32(total_err1);
-	total_err2 = _mm_srli_si128(total_err2,	4);							//  0   te1  te2  te3
-	total_err1 = _mm_srli_si128(total_err1, 4);							//  0    0    0   te1
-	total_error_3 = _mm_cvtsi128_si32(total_err2);
-	total_error_1 = _mm_cvtsi128_si32(total_err1);
-
-	/* prefer higher order */
-	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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
-		order = 1;
-	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;
-	else
-		order = 4;
-
-	/* Estimate the expected number of bits per residual signal sample. */
-	/* 'total_error*' is linearly related to the variance of the residual */
-	/* signal, so we use it directly to compute E(|x|) */
-	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
-
-	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
-
-	return order;
-}
-
-FLAC__SSE_TARGET("sse2")
-unsigned FLAC__fixed_compute_best_predictor_wide_intrin_sse2(const FLAC__int32 data[], unsigned data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
-{
-	FLAC__uint64 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
-	unsigned i, order;
-
-	__m128i total_err0, total_err1, total_err3;
-
-	{
-		FLAC__int32 itmp;
-		__m128i last_error, zero = _mm_setzero_si128();
-
-		last_error = _mm_cvtsi32_si128(data[-1]);							// 0   0   0   le0
-		itmp = data[-2];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   0   le0 le1
-		itmp -= data[-3];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   le0 le1 le2
-		itmp -= data[-3] - data[-4];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// le0 le1 le2 le3
-
-		total_err0 = total_err1 = total_err3 = _mm_setzero_si128();
-		for(i = 0; i < data_len; i++) {
-			__m128i err0, err1, tmp;
-			err0 = _mm_cvtsi32_si128(data[i]);								// 0   0   0   e0
-			err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(0,0,0,0));			// e0  e0  e0  e0
-#if 1 /* OPT_SSE */
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   le0 le1 le2
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   0   le0 le1
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   0   0   le0
-			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
-#else
-			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 8));	// le0  le1  le2+le0  le3+le1
-			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 4));	// le0  le1+le0  le2+le0+le1  le3+le1+le2+le0
-			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
-#endif
-			tmp = _mm_slli_si128(err0, 12);									// e0   0   0   0
-			last_error = _mm_srli_si128(err1, 4);							//  0  e1  e2  e3
-			last_error = _mm_or_si128(last_error, tmp);						// e0  e1  e2  e3
-
-			tmp = _mm_srai_epi32(err0, 31);
-			err0 = _mm_xor_si128(err0, tmp);
-			err0 = _mm_sub_epi32(err0, tmp);
-			tmp = _mm_srai_epi32(err1, 31);
-			err1 = _mm_xor_si128(err1, tmp);
-			err1 = _mm_sub_epi32(err1, tmp);
-
-			total_err0 = _mm_add_epi64(total_err0, err0);					//        0       te0
-			err0 = _mm_unpacklo_epi32(err1, zero);							//   0  |e3|   0  |e4|
-			err1 = _mm_unpackhi_epi32(err1, zero);							//   0  |e1|   0  |e2|
-			total_err3 = _mm_add_epi64(total_err3, err0);					//       te3      te4
-			total_err1 = _mm_add_epi64(total_err1, err1);					//       te1      te2
-		}
-	}
-
-	m128i_to_i64(total_error_0, total_err0);
-	m128i_to_i64(total_error_4, total_err3);
-	m128i_to_i64(total_error_2, total_err1);
-	total_err3 = _mm_srli_si128(total_err3,	8);							//         0      te3
-	total_err1 = _mm_srli_si128(total_err1, 8);							//         0      te1
-	m128i_to_i64(total_error_3, total_err3);
-	m128i_to_i64(total_error_1, total_err1);
-
-	/* prefer higher order */
-	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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
-		order = 1;
-	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;
-	else
-		order = 4;
-
-	/* Estimate the expected number of bits per residual signal sample. */
-	/* 'total_error*' is linearly related to the variance of the residual */
-	/* signal, so we use it directly to compute E(|x|) */
-	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
-
-	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
-
-	return order;
-}
-
-#endif /* FLAC__SSE2_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
-#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/libFLAC/fixed_intrin_ssse3.c b/libFLAC/fixed_intrin_ssse3.c
deleted file mode 100644
index f4d93e8..0000000
--- a/libFLAC/fixed_intrin_ssse3.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#include "private/fixed.h"
-#ifdef FLAC__SSSE3_SUPPORTED
-
-#include <tmmintrin.h> /* SSSE3 */
-#include <math.h>
-#include "private/macros.h"
-#include "share/compat.h"
-#include "FLAC/assert.h"
-
-#ifdef FLAC__CPU_IA32
-#define m128i_to_i64(dest, src) _mm_storel_epi64((__m128i*)&dest, src)
-#else
-#define m128i_to_i64(dest, src) dest = _mm_cvtsi128_si64(src)
-#endif
-
-FLAC__SSE_TARGET("ssse3")
-unsigned FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], unsigned data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
-{
-	FLAC__uint32 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
-	unsigned i, order;
-
-	__m128i total_err0, total_err1, total_err2;
-
-	{
-		FLAC__int32 itmp;
-		__m128i last_error;
-
-		last_error = _mm_cvtsi32_si128(data[-1]);							// 0   0   0   le0
-		itmp = data[-2];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   0   le0 le1
-		itmp -= data[-3];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   le0 le1 le2
-		itmp -= data[-3] - data[-4];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// le0 le1 le2 le3
-
-		total_err0 = total_err1 = _mm_setzero_si128();
-		for(i = 0; i < data_len; i++) {
-			__m128i err0, err1;
-			err0 = _mm_cvtsi32_si128(data[i]);								// 0   0   0   e0
-			err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(0,0,0,0));			// e0  e0  e0  e0
-#if 1 /* OPT_SSE */
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   le0 le1 le2
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   0   le0 le1
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   0   0   le0
-			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
-#else
-			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 8));	// le0  le1  le2+le0  le3+le1
-			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 4));	// le0  le1+le0  le2+le0+le1  le3+le1+le2+le0
-			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
-#endif
-			last_error = _mm_alignr_epi8(err0, err1, 4);					// e0  e1  e2  e3
-
-			err0 = _mm_abs_epi32(err0);
-			err1 = _mm_abs_epi32(err1);
-
-			total_err0 = _mm_add_epi32(total_err0, err0);					// 0   0   0   te0
-			total_err1 = _mm_add_epi32(total_err1, err1);					// te1 te2 te3 te4
-		}
-	}
-
-	total_error_0 = _mm_cvtsi128_si32(total_err0);
-	total_err2 = total_err1;											// te1  te2  te3  te4
-	total_err1 = _mm_srli_si128(total_err1, 8);							//  0    0   te1  te2
-	total_error_4 = _mm_cvtsi128_si32(total_err2);
-	total_error_2 = _mm_cvtsi128_si32(total_err1);
-	total_err2 = _mm_srli_si128(total_err2,	4);							//  0   te1  te2  te3
-	total_err1 = _mm_srli_si128(total_err1, 4);							//  0    0    0   te1
-	total_error_3 = _mm_cvtsi128_si32(total_err2);
-	total_error_1 = _mm_cvtsi128_si32(total_err1);
-
-	/* prefer higher order */
-	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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
-		order = 1;
-	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;
-	else
-		order = 4;
-
-	/* Estimate the expected number of bits per residual signal sample. */
-	/* 'total_error*' is linearly related to the variance of the residual */
-	/* signal, so we use it directly to compute E(|x|) */
-	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
-
-	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
-
-	return order;
-}
-
-FLAC__SSE_TARGET("ssse3")
-unsigned FLAC__fixed_compute_best_predictor_wide_intrin_ssse3(const FLAC__int32 data[], unsigned data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
-{
-	FLAC__uint64 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
-	unsigned i, order;
-
-	__m128i total_err0, total_err1, total_err3;
-
-	{
-		FLAC__int32 itmp;
-		__m128i last_error, zero = _mm_setzero_si128();
-
-		last_error = _mm_cvtsi32_si128(data[-1]);							// 0   0   0   le0
-		itmp = data[-2];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   0   le0 le1
-		itmp -= data[-3];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   le0 le1 le2
-		itmp -= data[-3] - data[-4];
-		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
-		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// le0 le1 le2 le3
-
-		total_err0 = total_err1 = total_err3 = _mm_setzero_si128();
-		for(i = 0; i < data_len; i++) {
-			__m128i err0, err1;
-			err0 = _mm_cvtsi32_si128(data[i]);								// 0   0   0   e0
-			err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(0,0,0,0));			// e0  e0  e0  e0
-#if 1 /* OPT_SSE */
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   le0 le1 le2
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   0   le0 le1
-			err1 = _mm_sub_epi32(err1, last_error);
-			last_error = _mm_srli_si128(last_error, 4);						// 0   0   0   le0
-			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
-#else
-			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 8));	// le0  le1  le2+le0  le3+le1
-			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 4));	// le0  le1+le0  le2+le0+le1  le3+le1+le2+le0
-			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
-#endif
-			last_error = _mm_alignr_epi8(err0, err1, 4);					// e0  e1  e2  e3
-
-			err0 = _mm_abs_epi32(err0);
-			err1 = _mm_abs_epi32(err1);										// |e1| |e2| |e3| |e4|
-
-			total_err0 = _mm_add_epi64(total_err0, err0);					//        0       te0
-			err0 = _mm_unpacklo_epi32(err1, zero);							//   0  |e3|   0  |e4|
-			err1 = _mm_unpackhi_epi32(err1, zero);							//   0  |e1|   0  |e2|
-			total_err3 = _mm_add_epi64(total_err3, err0);					//       te3      te4
-			total_err1 = _mm_add_epi64(total_err1, err1);					//       te1      te2
-		}
-	}
-
-	m128i_to_i64(total_error_0, total_err0);
-	m128i_to_i64(total_error_4, total_err3);
-	m128i_to_i64(total_error_2, total_err1);
-	total_err3 = _mm_srli_si128(total_err3,	8);							//         0      te3
-	total_err1 = _mm_srli_si128(total_err1, 8);							//         0      te1
-	m128i_to_i64(total_error_3, total_err3);
-	m128i_to_i64(total_error_1, total_err1);
-
-	/* prefer higher order */
-	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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
-		order = 1;
-	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;
-	else
-		order = 4;
-
-	/* Estimate the expected number of bits per residual signal sample. */
-	/* 'total_error*' is linearly related to the variance of the residual */
-	/* signal, so we use it directly to compute E(|x|) */
-	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
-	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
-
-	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
-	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
-
-	return order;
-}
-
-#endif /* FLAC__SSSE3_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
-#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/libFLAC/float.c b/libFLAC/float.c
deleted file mode 100644
index 25d1a78..0000000
--- a/libFLAC/float.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2004-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 */
diff --git a/libFLAC/format.c b/libFLAC/format.c
deleted file mode 100644
index 214bd09..0000000
--- a/libFLAC/format.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 <stdio.h>
-#include <stdlib.h> /* for qsort() */
-#include <string.h> /* for memset() */
-#include "FLAC/assert.h"
-#include "FLAC/format.h"
-#include "share/alloc.h"
-#include "share/compat.h"
-#include "private/format.h"
-#include "private/macros.h"
-
-/* PACKAGE_VERSION should come from configure */
-FLAC_API const char *FLAC__VERSION_STRING = PACKAGE_VERSION;
-
-FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " PACKAGE_VERSION " 20170101";
-
-FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
-FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143;
-FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */
-
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
-
-FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
-
-FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
-
-FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
-
-FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
-
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
-
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
-
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
-FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
-
-FLAC_API const unsigned FLAC__STREAM_METADATA_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 */
-
-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 = 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 */
-FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
-FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
-FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
-
-FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
-
-FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
-FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
-FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
-FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_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_RICE2"
-};
-
-FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
-FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
-
-FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
-FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
-FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
-
-FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
-FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
-FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
-FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
-
-FLAC_API const char * const FLAC__SubframeTypeString[] = {
-	"CONSTANT",
-	"VERBATIM",
-	"FIXED",
-	"LPC"
-};
-
-FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
-	"INDEPENDENT",
-	"LEFT_SIDE",
-	"RIGHT_SIDE",
-	"MID_SIDE"
-};
-
-FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
-	"FRAME_NUMBER_TYPE_FRAME_NUMBER",
-	"FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
-};
-
-FLAC_API const char * const FLAC__MetadataTypeString[] = {
-	"STREAMINFO",
-	"PADDING",
-	"APPLICATION",
-	"SEEKTABLE",
-	"VORBIS_COMMENT",
-	"CUESHEET",
-	"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(
-		!FLAC__format_sample_rate_is_valid(sample_rate) ||
-		(
-			sample_rate >= (1u << 16) &&
-			!(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
-		)
-	) {
-		return false;
-	}
-	else
-		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;
-	FLAC__uint64 prev_sample_number = 0;
-	FLAC__bool got_prev = false;
-
-	FLAC__ASSERT(0 != seek_table);
-
-	for(i = 0; i < seek_table->num_points; i++) {
-		if(got_prev) {
-			if(
-				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
-				seek_table->points[i].sample_number <= prev_sample_number
-			)
-				return false;
-		}
-		prev_sample_number = seek_table->points[i].sample_number;
-		got_prev = true;
-	}
-
-	return true;
-}
-
-/* used as the sort predicate for qsort() */
-static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
-{
-	/* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
-	if(l->sample_number == r->sample_number)
-		return 0;
-	else if(l->sample_number < r->sample_number)
-		return -1;
-	else
-		return 1;
-}
-
-/* @@@@ 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;
-	FLAC__bool first;
-
-	FLAC__ASSERT(0 != seek_table);
-
-	if (seek_table->num_points == 0)
-		return 0;
-
-	/* sort the seekpoints */
-	qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
-
-	/* uniquify the seekpoints */
-	first = true;
-	for(i = j = 0; i < seek_table->num_points; i++) {
-		if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
-			if(!first) {
-				if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
-					continue;
-			}
-		}
-		first = false;
-		seek_table->points[j++] = seek_table->points[i];
-	}
-
-	for(i = j; i < seek_table->num_points; i++) {
-		seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
-		seek_table->points[i].stream_offset = 0;
-		seek_table->points[i].frame_samples = 0;
-	}
-
-	return j;
-}
-
-/*
- * 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;
-
-	if(check_cd_da_subset) {
-		if(cue_sheet->lead_in < 2 * 44100) {
-			if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
-			return false;
-		}
-		if(cue_sheet->lead_in % 588 != 0) {
-			if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
-			return false;
-		}
-	}
-
-	if(cue_sheet->num_tracks == 0) {
-		if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
-		return false;
-	}
-
-	if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
-		if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
-		return false;
-	}
-
-	for(i = 0; i < cue_sheet->num_tracks; i++) {
-		if(cue_sheet->tracks[i].number == 0) {
-			if(violation) *violation = "cue sheet may not have a track number 0";
-			return false;
-		}
-
-		if(check_cd_da_subset) {
-			if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
-				if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
-				return false;
-			}
-		}
-
-		if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
-			if(violation) {
-				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;
-		}
-
-		if(i < cue_sheet->num_tracks - 1) {
-			if(cue_sheet->tracks[i].num_indices == 0) {
-				if(violation) *violation = "cue sheet track must have at least one index point";
-				return false;
-			}
-
-			if(cue_sheet->tracks[i].indices[0].number > 1) {
-				if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
-				return false;
-			}
-		}
-
-		for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
-			if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
-				if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
-				return false;
-			}
-
-			if(j > 0) {
-				if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
-					if(violation) *violation = "cue sheet track index numbers must increase by 1";
-					return false;
-				}
-			}
-		}
-	}
-
-	return true;
-}
-
-/* @@@@ 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
- */
-unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
-{
-	return
-		FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
-			FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
-			blocksize,
-			predictor_order
-		);
-}
-
-unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
-{
-	unsigned max_rice_partition_order = 0;
-	while(!(blocksize & 1)) {
-		max_rice_partition_order++;
-		blocksize >>= 1;
-	}
-	return 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)
-{
-	unsigned max_rice_partition_order = limit;
-
-	while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
-		max_rice_partition_order--;
-
-	FLAC__ASSERT(
-		(max_rice_partition_order == 0 && blocksize >= predictor_order) ||
-		(max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
-	);
-
-	return max_rice_partition_order;
-}
-
-void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
-{
-	FLAC__ASSERT(0 != object);
-
-	object->parameters = 0;
-	object->raw_bits = 0;
-	object->capacity_by_order = 0;
-}
-
-void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
-{
-	FLAC__ASSERT(0 != object);
-
-	if(0 != object->parameters)
-		free(object->parameters);
-	if(0 != object->raw_bits)
-		free(object->raw_bits);
-	FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
-}
-
-FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order)
-{
-	FLAC__ASSERT(0 != object);
-
-	FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
-
-	if(object->capacity_by_order < max_partition_order) {
-		if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
-			return false;
-		if(0 == (object->raw_bits = safe_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;
-	}
-
-	return true;
-}
diff --git a/libFLAC/include/private/bitmath.h b/libFLAC/include/private/bitmath.h
deleted file mode 100644
index 9c75f85..0000000
--- a/libFLAC/include/private/bitmath.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__BITMATH_H
-#define FLAC__PRIVATE__BITMATH_H
-
-#include "FLAC/ordinals.h"
-#include "FLAC/assert.h"
-
-#include "share/compat.h"
-
-#if defined(_MSC_VER)
-#include <intrin.h> /* for _BitScanReverse* */
-#endif
-
-/* Will never be emitted for MSVC, GCC, Intel compilers */
-static inline unsigned int FLAC__clz_soft_uint32(FLAC__uint32 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)
-	{
-		unsigned long idx;
-		_BitScanReverse(&idx, v);
-		return idx ^ 31U;
-	}
-#else
-	return FLAC__clz_soft_uint32(v);
-#endif
-}
-
-/* Used when 64-bit bsr/clz is unavailable; can use 32-bit bsr/clz when possible */
-static inline unsigned int FLAC__clz_soft_uint64(FLAC__uint64 word)
-{
-	return (FLAC__uint32)(word>>32) ? FLAC__clz_uint32((FLAC__uint32)(word>>32)) :
-		FLAC__clz_uint32((FLAC__uint32)word) + 32;
-}
-
-static inline unsigned int FLAC__clz_uint64(FLAC__uint64 v)
-{
-	/* Never used with input 0 */
-	FLAC__ASSERT(v > 0);
-#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-	return __builtin_clzll(v);
-#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
-	{
-		unsigned long idx;
-		_BitScanReverse64(&idx, v);
-		return idx ^ 63U;
-	}
-#else
-	return FLAC__clz_soft_uint64(v);
-#endif
-}
-
-/* These two functions work with input 0 */
-static inline unsigned int FLAC__clz2_uint32(FLAC__uint32 v)
-{
-	if (!v)
-		return 32;
-	return FLAC__clz_uint32(v);
-}
-
-static inline unsigned int FLAC__clz2_uint64(FLAC__uint64 v)
-{
-	if (!v)
-		return 64;
-	return FLAC__clz_uint64(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)
-	{
-		unsigned long idx;
-		_BitScanReverse(&idx, v);
-		return idx;
-	}
-#else
-	return FLAC__clz_uint32(v) ^ 31U;
-#endif
-}
-
-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 __builtin_clzll(v) ^ 63U;
-/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */
-#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (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 (tterribe@xiph.org) 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*FLAC__U64L(0x218A392CD3D5DBF)>>58&0x3F];
-	}
-#endif
-}
-
-unsigned FLAC__bitmath_silog2(FLAC__int64 v);
-
-#endif
diff --git a/libFLAC/include/private/bitreader.h b/libFLAC/include/private/bitreader.h
deleted file mode 100644
index 7c73165..0000000
--- a/libFLAC/include/private/bitreader.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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
diff --git a/libFLAC/include/private/bitwriter.h b/libFLAC/include/private/bitwriter.h
deleted file mode 100644
index ef3ad1b..0000000
--- a/libFLAC/include/private/bitwriter.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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
diff --git a/libFLAC/include/private/cpu.h b/libFLAC/include/private/cpu.h
deleted file mode 100644
index 7c65180..0000000
--- a/libFLAC/include/private/cpu.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__CPU_H
-#define FLAC__PRIVATE__CPU_H
-
-#include "FLAC/ordinals.h"
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifndef FLAC__CPU_X86_64
-
-#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
-#define FLAC__CPU_X86_64
-#endif
-
-#endif
-
-#ifndef FLAC__CPU_IA32
-
-#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)
-#define FLAC__CPU_IA32
-#endif
-
-#endif
-
-
-#if 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
-#ifdef FLAC__USE_AVX
-    #define FLAC__AVX_SUPPORTED 1
-    #define FLAC__AVX2_SUPPORTED 1
-    #define FLAC__FMA_SUPPORTED 1
-#endif
-  #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 */
-
-
-#ifndef FLAC__AVX_SUPPORTED
-#define FLAC__AVX_SUPPORTED 0
-#endif
-
-typedef enum {
-	FLAC__CPUINFO_TYPE_IA32,
-	FLAC__CPUINFO_TYPE_X86_64,
-	FLAC__CPUINFO_TYPE_UNKNOWN
-} FLAC__CPUInfo_Type;
-
-typedef struct {
-	FLAC__bool intel;
-
-	FLAC__bool cmov;
-	FLAC__bool mmx;
-	FLAC__bool sse;
-	FLAC__bool sse2;
-
-	FLAC__bool sse3;
-	FLAC__bool ssse3;
-	FLAC__bool sse41;
-	FLAC__bool sse42;
-	FLAC__bool avx;
-	FLAC__bool avx2;
-	FLAC__bool fma;
-} FLAC__CPUInfo_IA32;
-
-typedef struct {
-	FLAC__bool intel;
-
-	FLAC__bool sse3;
-	FLAC__bool ssse3;
-	FLAC__bool sse41;
-	FLAC__bool sse42;
-	FLAC__bool avx;
-	FLAC__bool avx2;
-	FLAC__bool fma;
-} FLAC__CPUInfo_x86;
-
-
-typedef struct {
-	FLAC__bool use_asm;
-	FLAC__CPUInfo_Type type;
-	FLAC__CPUInfo_IA32 ia32;
-	FLAC__CPUInfo_x86 x86;
-} FLAC__CPUInfo;
-
-void FLAC__cpu_info(FLAC__CPUInfo *info);
-
-FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void);
-
-void         FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx);
-
-void         FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx);
-
-#endif
diff --git a/libFLAC/include/private/crc.h b/libFLAC/include/private/crc.h
deleted file mode 100644
index 294f60e..0000000
--- a/libFLAC/include/private/crc.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__CRC_H
-#define FLAC__PRIVATE__CRC_H
-
-#include "FLAC/ordinals.h"
-
-/* 8 bit CRC generator, MSB shifted first
-** polynomial = x^8 + x^2 + x^1 + x^0
-** init = 0
-*/
-extern FLAC__byte const FLAC__crc8_table[256];
-#define FLAC__CRC8_UPDATE(data, crc) (crc) = FLAC__crc8_table[(crc) ^ (data)];
-void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc);
-void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc);
-FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len);
-
-/* 16 bit CRC generator, MSB shifted first
-** polynomial = x^16 + x^15 + x^2 + x^0
-** init = 0
-*/
-extern 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
diff --git a/libFLAC/include/private/fixed.h b/libFLAC/include/private/fixed.h
deleted file mode 100644
index 68cdfce..0000000
--- a/libFLAC/include/private/fixed.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__FIXED_H
-#define FLAC__PRIVATE__FIXED_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()
- *	--------------------------------------------------------------------
- *	Compute the best fixed predictor and the expected bits-per-sample
- *  of the residual signal for each order.  The _wide() version uses
- *  64-bit integers which is statistically necessary when bits-per-
- *  sample + log2(blocksize) > 30
- *
- *	IN data[0,data_len-1]
- *	IN data_len
- *	OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER]
- */
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
-unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
-# ifndef FLAC__NO_ASM
-#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#   ifdef FLAC__SSE2_SUPPORTED
-unsigned FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], unsigned data_len, 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, 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, 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, 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, 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
-
-/*
- *	FLAC__fixed_compute_residual()
- *	--------------------------------------------------------------------
- *	Compute the residual signal obtained from sutracting the predicted
- *	signal from the original.
- *
- *	IN data[-order,data_len-1]        original signal (NOTE THE INDICES!)
- *	IN data_len                       length of original signal
- *	IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
- *	OUT residual[0,data_len-1]        residual signal
- */
-void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]);
-
-/*
- *	FLAC__fixed_restore_signal()
- *	--------------------------------------------------------------------
- *	Restore the original signal by summing the residual and the
- *	predictor.
- *
- *	IN residual[0,data_len-1]         residual signal
- *	IN data_len                       length of original signal
- *	IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
- *	*** IMPORTANT: the caller must pass in the historical samples:
- *	IN  data[-order,-1]               previously-reconstructed historical samples
- *	OUT data[0,data_len-1]            original signal
- */
-void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]);
-
-#endif
diff --git a/libFLAC/include/private/float.h b/libFLAC/include/private/float.h
deleted file mode 100644
index 12ece60..0000000
--- a/libFLAC/include/private/float.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2004-2009  Josh Coalson
- * Copyright (C) 2011-2016  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"
-
-/*
- * All the code in libFLAC that uses float and double
- * should be protected by checks of the macro
- * FLAC__INTEGER_ONLY_LIBRARY.
- *
- */
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-/*
- * FLAC__real is the basic floating point type used in LPC analysis.
- *
- * 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
diff --git a/libFLAC/include/private/format.h b/libFLAC/include/private/format.h
deleted file mode 100644
index 5b9cfbd..0000000
--- a/libFLAC/include/private/format.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__FORMAT_H
-#define FLAC__PRIVATE__FORMAT_H
-
-#include "FLAC/format.h"
-
-unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order);
-unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize);
-unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order);
-void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
-void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
-FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order);
-
-#endif
diff --git a/libFLAC/include/private/lpc.h b/libFLAC/include/private/lpc.h
deleted file mode 100644
index 6eb02be..0000000
--- a/libFLAC/include/private/lpc.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__LPC_H
-#define FLAC__PRIVATE__LPC_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.
- *	Assumes data[] outside of [0,data_len-1] == 0.
- *	Asserts that lag > 0.
- *
- *	IN data[0,data_len-1]
- *	IN data_len
- *	IN 0 < lag <= data_len
- *	OUT autoc[0,lag-1]
- */
-void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-#ifndef FLAC__NO_ASM
-#  ifdef FLAC__CPU_IA32
-#    ifdef FLAC__HAS_NASM
-void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-#    endif
-#  endif
-#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#    ifdef FLAC__SSE_SUPPORTED
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
-#    endif
-#  endif
-#endif
-
-/*
- *	FLAC__lpc_compute_lp_coefficients()
- *	--------------------------------------------------------------------
- *	Computes LP coefficients for orders 1..max_order.
- *	Do not call if autoc[0] == 0.0.  This means the signal is zero
- *	and there is no point in calculating a predictor.
- *
- *	IN autoc[0,max_order]                      autocorrelation values
- *	IN 0 < max_order <= FLAC__MAX_LPC_ORDER    max LP order to compute
- *	OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order
- *	*** IMPORTANT:
- *	*** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched
- *	OUT error[0,max_order-1]                   error for each order (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], double error[]);
-
-/*
- *	FLAC__lpc_quantize_coefficients()
- *	--------------------------------------------------------------------
- *	Quantizes the LP coefficients.  NOTE: precision + bits_per_sample
- *	must be less than 32 (sizeof(FLAC__int32)*8).
- *
- *	IN lp_coeff[0,order-1]    LP coefficients
- *	IN order                  LP order
- *	IN FLAC__MIN_QLP_COEFF_PRECISION < precision
- *	                          desired precision (in bits, including sign
- *	                          bit) of largest coefficient
- *	OUT qlp_coeff[0,order-1]  quantized coefficients
- *	OUT shift                 # of bits to shift right to get approximated
- *	                          LP coefficients.  NOTE: could be negative.
- *	RETURN 0 => quantization OK
- *	       1 => coefficients require too much shifting for *shift to
- *              fit in the LPC subframe header.  'shift' is unset.
- *         2 => coefficients are all zero, which is bad.  'shift' is
- *              unset.
- */
-int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift);
-
-/*
- *	FLAC__lpc_compute_residual_from_qlp_coefficients()
- *	--------------------------------------------------------------------
- *	Compute the residual signal obtained from sutracting the predicted
- *	signal from the original.
- *
- *	IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
- *	IN data_len                length of original signal
- *	IN qlp_coeff[0,order-1]    quantized LP coefficients
- *	IN order > 0               LP order
- *	IN lp_quantization         quantization of LP coefficients in bits
- *	OUT residual[0,data_len-1] residual signal
- */
-void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
-void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
-#ifndef FLAC__NO_ASM
-#  ifdef FLAC__CPU_IA32
-#    ifdef FLAC__HAS_NASM
-void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
-void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
-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) && 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 /* !defined FLAC__INTEGER_ONLY_LIBRARY */
-
-/*
- *	FLAC__lpc_restore_signal()
- *	--------------------------------------------------------------------
- *	Restore the original signal by summing the residual and the
- *	predictor.
- *
- *	IN residual[0,data_len-1]  residual signal
- *	IN data_len                length of original signal
- *	IN qlp_coeff[0,order-1]    quantized LP coefficients
- *	IN order > 0               LP order
- *	IN lp_quantization         quantization of LP coefficients in bits
- *	*** IMPORTANT: the caller must pass in the historical samples:
- *	IN  data[-order,-1]        previously-reconstructed historical samples
- *	OUT data[0,data_len-1]     original signal
- */
-void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
-void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
-#ifndef FLAC__NO_ASM
-#  ifdef FLAC__CPU_IA32
-#    ifdef FLAC__HAS_NASM
-void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
-void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
-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) && 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()
- *	--------------------------------------------------------------------
- *	Compute the expected number of bits per residual signal sample
- *	based on the LP error (which is related to the residual variance).
- *
- *	IN lpc_error >= 0.0   error returned from calculating LP coefficients
- *	IN total_samples > 0  # of samples in residual signal
- *	RETURN                expected bits per sample
- */
-double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, unsigned total_samples);
-double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale);
-
-/*
- *	FLAC__lpc_compute_best_order()
- *	--------------------------------------------------------------------
- *	Compute the best order from the array of signal errors returned
- *	during coefficient computation.
- *
- *	IN lpc_error[0,max_order-1] >= 0.0  error returned from calculating LP coefficients
- *	IN max_order > 0                    max LP order
- *	IN total_samples > 0                # of samples in residual signal
- *	IN 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 double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order);
-
-#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
-
-#endif
diff --git a/libFLAC/include/private/macros.h b/libFLAC/include/private/macros.h
deleted file mode 100644
index becc59f..0000000
--- a/libFLAC/include/private/macros.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2012-2016  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
-
-#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
diff --git a/libFLAC/include/private/md5.h b/libFLAC/include/private/md5.h
deleted file mode 100644
index c665ab3..0000000
--- a/libFLAC/include/private/md5.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#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
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- *
- * Changed so as no longer to depend on Colin Plumb's `usual.h'
- * header definitions; now uses stuff from dpkg's config.h
- *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
- * Still in the public domain.
- *
- * Josh Coalson: made some changes to integrate with libFLAC.
- * Still in the public domain, with no warranty.
- */
-
-#include "FLAC/ordinals.h"
-
-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__multibyte internal_buf;
-	size_t capacity;
-} FLAC__MD5Context;
-
-void FLAC__MD5Init(FLAC__MD5Context *context);
-void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context);
-
-FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
-
-#endif
diff --git a/libFLAC/include/private/memory.h b/libFLAC/include/private/memory.h
deleted file mode 100644
index f103c53..0000000
--- a/libFLAC/include/private/memory.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__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.
- * 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(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
diff --git a/libFLAC/include/private/ogg_decoder_aspect.h b/libFLAC/include/private/ogg_decoder_aspect.h
deleted file mode 100644
index 218f44e..0000000
--- a/libFLAC/include/private/ogg_decoder_aspect.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec
- * Copyright (C) 2002-2009  Josh Coalson
- * Copyright (C) 2011-2016  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
diff --git a/libFLAC/include/private/ogg_encoder_aspect.h b/libFLAC/include/private/ogg_encoder_aspect.h
deleted file mode 100644
index f55ef32..0000000
--- a/libFLAC/include/private/ogg_encoder_aspect.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec
- * Copyright (C) 2002-2009  Josh Coalson
- * Copyright (C) 2011-2016  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
diff --git a/libFLAC/include/private/ogg_mapping.h b/libFLAC/include/private/ogg_mapping.h
deleted file mode 100644
index 1fa022d..0000000
--- a/libFLAC/include/private/ogg_mapping.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec
- * Copyright (C) 2004-2009  Josh Coalson
- * Copyright (C) 2011-2016  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
diff --git a/libFLAC/include/private/stream_encoder.h b/libFLAC/include/private/stream_encoder.h
deleted file mode 100644
index ab1721f..0000000
--- a/libFLAC/include/private/stream_encoder.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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
diff --git a/libFLAC/include/private/stream_encoder_framing.h b/libFLAC/include/private/stream_encoder_framing.h
deleted file mode 100644
index f633a9d..0000000
--- a/libFLAC/include/private/stream_encoder_framing.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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_FRAMING_H
-#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
-
-#include "FLAC/format.h"
-#include "bitwriter.h"
-
-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
diff --git a/libFLAC/include/protected/stream_decoder.h b/libFLAC/include/protected/stream_decoder.h
deleted file mode 100644
index 5c31c16..0000000
--- a/libFLAC/include/protected/stream_decoder.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__PROTECTED__STREAM_DECODER_H
-#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;
-
-/*
- * return the number of input bytes consumed
- */
-unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder);
-
-#endif
diff --git a/libFLAC/include/protected/stream_encoder.h b/libFLAC/include/protected/stream_encoder.h
deleted file mode 100644
index 8850c6b..0000000
--- a/libFLAC/include/protected/stream_encoder.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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__PROTECTED__STREAM_ENCODER_H
-#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 // #ifndef FLAC__INTEGER_ONLY_LIBRARY
-
-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;
-	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;
-	FLAC__bool do_exhaustive_model_search;
-	FLAC__bool do_escape_coding;
-	unsigned min_residual_partition_order;
-	unsigned max_residual_partition_order;
-	unsigned rice_parameter_search_dist;
-	FLAC__uint64 total_samples_estimate;
-	FLAC__StreamMetadata **metadata;
-	unsigned num_metadata_blocks;
-	FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset;
-#if FLAC__HAS_OGG
-	FLAC__OggEncoderAspect ogg_encoder_aspect;
-#endif
-} FLAC__StreamEncoderProtected;
-
-#endif
diff --git a/libFLAC/libFLAC.m4 b/libFLAC/libFLAC.m4
deleted file mode 100644
index da7354e..0000000
--- a/libFLAC/libFLAC.m4
+++ /dev/null
@@ -1,118 +0,0 @@
-# Configure paths for libFLAC
-# "Inspired" by ogg.m4
-
-dnl AM_PATH_LIBFLAC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
-dnl Test for libFLAC, and define LIBFLAC_CFLAGS, LIBFLAC_LIBS, LIBFLAC_LIBDIR
-dnl
-AC_DEFUN([AM_PATH_LIBFLAC],
-[dnl 
-dnl Get the cflags and libraries
-dnl
-AC_ARG_WITH(libFLAC,[  --with-libFLAC=PFX   Prefix where libFLAC is installed (optional)], libFLAC_prefix="$withval", libFLAC_prefix="")
-AC_ARG_WITH(libFLAC-libraries,[  --with-libFLAC-libraries=DIR   Directory where libFLAC library is installed (optional)], libFLAC_libraries="$withval", libFLAC_libraries="")
-AC_ARG_WITH(libFLAC-includes,[  --with-libFLAC-includes=DIR   Directory where libFLAC header files are installed (optional)], libFLAC_includes="$withval", libFLAC_includes="")
-AC_ARG_ENABLE(libFLACtest, [  --disable-libFLACtest       Do not try to compile and run a test libFLAC program],, enable_libFLACtest=yes)
-
-  if test "x$libFLAC_libraries" != "x" ; then
-    LIBFLAC_LIBS="-L$libFLAC_libraries"
-  elif test "x$libFLAC_prefix" = "xno" || test "x$libFLAC_prefix" = "xyes" ; then
-    LIBFLAC_LIBS=""
-  elif test "x$libFLAC_prefix" != "x" ; then
-    LIBFLAC_LIBS="-L$libFLAC_prefix/lib"
-  elif test "x$prefix" != "xNONE"; then
-    LIBFLAC_LIBS="-L$prefix/lib"
-  fi
-
-  if test "x$libFLAC_prefix" != "xno" ; then
-    LIBFLAC_LIBS="$LIBFLAC_LIBS -lFLAC $OGG_LIBS -lm"
-  fi
-
-  if test "x$libFLAC_includes" != "x" ; then
-    LIBFLAC_CFLAGS="-I$libFLAC_includes"
-  elif test "x$libFLAC_prefix" != "x" ; then
-    LIBFLAC_CFLAGS="-I$libFLAC_prefix/include"
-  elif test "$prefix" != "xNONE"; then
-    LIBFLAC_CFLAGS=""
-  fi
-
-  AC_MSG_CHECKING(for libFLAC)
-  no_libFLAC=""
-
-
-  if test "x$enable_libFLACtest" = "xyes" ; then
-    ac_save_CFLAGS="$CFLAGS"
-    ac_save_CXXFLAGS="$CXXFLAGS"
-    ac_save_LIBS="$LIBS"
-    ac_save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
-    CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
-    CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
-    LIBS="$LIBS $LIBFLAC_LIBS"
-    LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
-dnl
-dnl Now check if the installed libFLAC is sufficiently new.
-dnl
-      rm -f conf.libFLACtest
-      AC_TRY_RUN([
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <FLAC/format.h>
-
-int main ()
-{
-  system("touch conf.libFLACtest");
-  return 0;
-}
-
-],, no_libFLAC=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
-       CFLAGS="$ac_save_CFLAGS"
-       CXXFLAGS="$ac_save_CXXFLAGS"
-       LIBS="$ac_save_LIBS"
-       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
-  fi
-
-  if test "x$no_libFLAC" = "x" ; then
-     AC_MSG_RESULT(yes)
-     ifelse([$1], , :, [$1])     
-  else
-     AC_MSG_RESULT(no)
-     if test -f conf.libFLACtest ; then
-       :
-     else
-       echo "*** Could not run libFLAC test program, checking why..."
-       CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
-       CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
-       LIBS="$LIBS $LIBFLAC_LIBS"
-       LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
-       AC_TRY_LINK([
-#include <stdio.h>
-#include <FLAC/format.h>
-],     [ return 0; ],
-       [ echo "*** The test program compiled, but did not run. This usually means"
-       echo "*** that the run-time linker is not finding libFLAC or finding the wrong"
-       echo "*** version of libFLAC. If it is not finding libFLAC, you'll need to set your"
-       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
-       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
-       echo "*** is required on your system"
-       echo "***"
-       echo "*** If you have an old version installed, it is best to remove it, although"
-       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
-       [ echo "*** The test program failed to compile or link. See the file config.log for the"
-       echo "*** exact error that occured. This usually means libFLAC was incorrectly installed"
-       echo "*** or that you have moved libFLAC since it was installed. In the latter case, you"
-       echo "*** may want to edit the libFLAC-config script: $LIBFLAC_CONFIG" ])
-       CFLAGS="$ac_save_CFLAGS"
-       CXXFLAGS="$ac_save_CXXFLAGS"
-       LIBS="$ac_save_LIBS"
-       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
-     fi
-     LIBFLAC_CFLAGS=""
-     LIBFLAC_LIBDIR=""
-     LIBFLAC_LIBS=""
-     ifelse([$2], , :, [$2])
-  fi
-  AC_SUBST(LIBFLAC_CFLAGS)
-  AC_SUBST(LIBFLAC_LIBDIR)
-  AC_SUBST(LIBFLAC_LIBS)
-  rm -f conf.libFLACtest
-])
diff --git a/libFLAC/libFLAC_blacklist.txt b/libFLAC/libFLAC_blacklist.txt
deleted file mode 100644
index 9b0d7d2..0000000
--- a/libFLAC/libFLAC_blacklist.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-[integer]
-# Preemptive due to: while(lag--)
-fun:FLAC__lpc_compute_autocorrelation
-# libFLAC/stream_encoder.c:3982: 4294967292 + 128 cannot be represented in type 'unsigned int'
-fun:precompute_partition_info_sums_
-# libFLAC/lpc.c:1030:18: -1932902714 + -1376235516 cannot be represented in type 'int'
-fun:FLAC__lpc_restore_signal
-# libFLAC/fixed.c:390:44: 6 * -358419632 cannot be represented in type 'int'
-# libFLAC/fixed.c:378:27: -1023409921 + -1145670695 cannot be represented in type 'int'
-fun:FLAC__fixed_restore_signal
-fun:FLAC__fixed_compute_residual
-
-src:*/libFLAC/crc.c
-src:*/libFLAC/md5.c
-src:*/libFLAC/bitmath.c
-src:*/libFLAC/bitreader.c
-src:*/libFLAC/bitwriter.c
-
-# Performance related
-fun:FLAC__lpc_restore_signal_wide
diff --git a/libFLAC/lpc.c b/libFLAC/lpc.c
deleted file mode 100644
index 531247b..0000000
--- a/libFLAC/lpc.c
+++ /dev/null
@@ -1,1357 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 "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
-
-/* OPT: #undef'ing this may improve the speed on some architectures */
-#define FLAC__LPC_UNROLLED_FILTER_LOOPS
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-
-#if defined(_MSC_VER) && (_MSC_VER < 1800)
-#include <float.h>
-static inline long int lround(double x) {
-	return (long)(x + _copysign(0.5, x));
-}
-#elif !defined(HAVE_LROUND) && defined(__GNUC__)
-static inline long int lround(double x) {
-	return (long)(x + __builtin_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 */
-#if 0
-	FLAC__real d;
-	unsigned i;
-
-	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];
-		autoc[lag] = d;
-	}
-#endif
-
-	/*
-	 * this version tends to run faster because of better data locality
-	 * ('data_len' is usually much larger than 'lag')
-	 */
-	FLAC__real d;
-	unsigned sample, coeff;
-	const unsigned limit = data_len - lag;
-
-	FLAC__ASSERT(lag > 0);
-	FLAC__ASSERT(lag <= data_len);
-
-	for(coeff = 0; coeff < lag; coeff++)
-		autoc[coeff] = 0.0;
-	for(sample = 0; sample <= limit; sample++) {
-		d = data[sample];
-		for(coeff = 0; coeff < lag; coeff++)
-			autoc[coeff] += d * data[sample+coeff];
-	}
-	for(; sample < data_len; sample++) {
-		d = data[sample];
-		for(coeff = 0; coeff < data_len - sample; coeff++)
-			autoc[coeff] += d * data[sample+coeff];
-	}
-}
-
-void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[])
-{
-	unsigned i, j;
-	double r, err, lpc[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++) {
-		/* Sum up this iteration's reflection coefficient. */
-		r = -autoc[i+1];
-		for(j = 0; j < i; j++)
-			r -= lpc[j] * autoc[i-j];
-		r /= err;
-
-		/* Update LPC coefficients and total error. */
-		lpc[i]=r;
-		for(j = 0; j < (i>>1); j++) {
-			double tmp = lpc[j];
-			lpc[j] += r * lpc[i-1-j];
-			lpc[i-1-j] += r * tmp;
-		}
-		if(i & 1)
-			lpc[j] += lpc[j] * r;
-
-		err *= (1.0 - r * r);
-
-		/* save this order */
-		for(j = 0; j <= i; j++)
-			lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
-		error[i] = err;
-
-		/* see SF bug https://sourceforge.net/p/flac/bugs/234/ */
-		if(err == 0.0) {
-			*max_order = i+1;
-			return;
-		}
-	}
-}
-
-int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift)
-{
-	unsigned i;
-	double cmax;
-	FLAC__int32 qmax, qmin;
-
-	FLAC__ASSERT(precision > 0);
-	FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
-
-	/* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
-	precision--;
-	qmax = 1 << precision;
-	qmin = -qmax;
-	qmax--;
-
-	/* calc cmax = max( |lp_coeff[i]| ) */
-	cmax = 0.0;
-	for(i = 0; i < order; i++) {
-		const double d = fabs(lp_coeff[i]);
-		if(d > cmax)
-			cmax = d;
-	}
-
-	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);
-		log2cmax--;
-		*shift = (int)precision - log2cmax - 1;
-
-		if(*shift > max_shiftlimit)
-			*shift = max_shiftlimit;
-		else if(*shift < min_shiftlimit)
-			return 1;
-	}
-
-	if(*shift >= 0) {
-		double error = 0.0;
-		FLAC__int32 q;
-		for(i = 0; i < order; i++) {
-			error += lp_coeff[i] * (1 << *shift);
-			q = lround(error);
-
-#ifdef FLAC__OVERFLOW_DETECT
-			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
-			if(q > qmax)
-				q = qmax;
-			else if(q < qmin)
-				q = qmin;
-			error -= q;
-			qlp_coeff[i] = q;
-		}
-	}
-	/* negative shift is very rare but due to design flaw, negative shift is
-	 * not allowed in the decoder, so it must be handled specially by scaling
-	 * down coeffs
-	 */
-	else {
-		const int nshift = -(*shift);
-		double error = 0.0;
-		FLAC__int32 q;
-#ifdef DEBUG
-		fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax);
-#endif
-		for(i = 0; i < order; i++) {
-			error += lp_coeff[i] / (1 << nshift);
-			q = lround(error);
-#ifdef FLAC__OVERFLOW_DETECT
-			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
-			if(q > qmax)
-				q = qmax;
-			else if(q < qmin)
-				q = qmin;
-			error -= q;
-			qlp_coeff[i] = q;
-		}
-		*shift = 0;
-	}
-
-	return 0;
-}
-
-#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)
-{
-	FLAC__int64 sumo;
-	unsigned i, j;
-	FLAC__int32 sum;
-	const FLAC__int32 *history;
-
-#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
-	fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
-	for(i=0;i<order;i++)
-		fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
-	fprintf(stderr,"\n");
-#endif
-	FLAC__ASSERT(order > 0);
-
-	for(i = 0; i < data_len; i++) {
-		sumo = 0;
-		sum = 0;
-		history = data;
-		for(j = 0; j < order; j++) {
-			sum += qlp_coeff[j] * (*(--history));
-			sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
-			if(sumo > 2147483647ll || sumo < -2147483648ll)
-				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);
-	}
-
-	/* Here's a slower but clearer version:
-	for(i = 0; i < data_len; i++) {
-		sum = 0;
-		for(j = 0; j < order; j++)
-			sum += qlp_coeff[j] * data[i-j-1];
-		residual[i] = data[i] - (sum >> lp_quantization);
-	}
-	*/
-}
-#else /* fully unrolled version for normal use */
-{
-	int i;
-	FLAC__int32 sum;
-
-	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;
-	const FLAC__int32 *history;
-
-#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
-	fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
-	for(i=0;i<order;i++)
-		fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
-	fprintf(stderr,"\n");
-#endif
-	FLAC__ASSERT(order > 0);
-
-	for(i = 0; i < data_len; i++) {
-		sum = 0;
-		history = data;
-		for(j = 0; j < order; j++)
-			sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
-		if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) {
-			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((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
-			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;
-		}
-		*(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
-	}
-}
-#else /* fully unrolled version for normal use */
-{
-	int i;
-	FLAC__int64 sum;
-
-	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)
-{
-	FLAC__int64 sumo;
-	unsigned i, j;
-	FLAC__int32 sum;
-	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);
-	for(i=0;i<order;i++)
-		fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
-	fprintf(stderr,"\n");
-#endif
-	FLAC__ASSERT(order > 0);
-
-	for(i = 0; i < data_len; i++) {
-		sumo = 0;
-		sum = 0;
-		history = data;
-		for(j = 0; j < order; j++) {
-			sum += qlp_coeff[j] * (*(--history));
-			sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
-			if(sumo > 2147483647ll || sumo < -2147483648ll)
-				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++) = *(r++) + (sum >> lp_quantization);
-	}
-
-	/* Here's a slower but clearer version:
-	for(i = 0; i < data_len; i++) {
-		sum = 0;
-		for(j = 0; j < order; j++)
-			sum += qlp_coeff[j] * data[i-j-1];
-		data[i] = residual[i] + (sum >> lp_quantization);
-	}
-	*/
-}
-#else /* fully unrolled version for normal use */
-{
-	int i;
-	FLAC__int32 sum;
-
-	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 *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);
-	for(i=0;i<order;i++)
-		fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
-	fprintf(stderr,"\n");
-#endif
-	FLAC__ASSERT(order > 0);
-
-	for(i = 0; i < data_len; i++) {
-		sum = 0;
-		history = data;
-		for(j = 0; j < order; j++)
-			sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
-		if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) {
-			fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization));
-			break;
-		}
-		if(FLAC__bitmath_silog2((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;
-		}
-		*(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization);
-	}
-}
-#else /* fully unrolled version for normal use */
-{
-	int i;
-	FLAC__int64 sum;
-
-	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
-
-double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, unsigned total_samples)
-{
-	double error_scale;
-
-	FLAC__ASSERT(total_samples > 0);
-
-	error_scale = 0.5 / (double)total_samples;
-
-	return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
-}
-
-double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale)
-{
-	if(lpc_error > 0.0) {
-		double bps = (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 floating-point resolution */
-		return 1e32;
-	}
-	else {
-		return 0.0;
-	}
-}
-
-unsigned FLAC__lpc_compute_best_order(const double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order)
-{
-	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 */
-	double bits, best_bits, error_scale;
-
-	FLAC__ASSERT(max_order > 0);
-	FLAC__ASSERT(total_samples > 0);
-
-	error_scale = 0.5 / (double)total_samples;
-
-	best_index = 0;
-	best_bits = (unsigned)(-1);
-
-	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) * (double)(total_samples - order) + (double)(order * overhead_bits_per_order);
-		if(bits < best_bits) {
-			best_index = indx;
-			best_bits = bits;
-		}
-	}
-
-	return best_index+1; /* +1 since indx of lpc_error[] is order-1 */
-}
-
-#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/libFLAC/lpc_intrin_avx2.c b/libFLAC/lpc_intrin_avx2.c
deleted file mode 100644
index f9f5ccd..0000000
--- a/libFLAC/lpc_intrin_avx2.c
+++ /dev/null
@@ -1,1122 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#include "private/lpc.h"
-#ifdef FLAC__AVX2_SUPPORTED
-
-#include "FLAC/assert.h"
-#include "FLAC/format.h"
-
-#include <immintrin.h> /* AVX2 */
-
-FLAC__SSE_TARGET("avx2")
-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[])
-{
-	int i;
-	FLAC__int32 sum;
-	__m128i cnt = _mm_cvtsi32_si128(lp_quantization);
-
-	FLAC__ASSERT(order > 0);
-	FLAC__ASSERT(order <= 32);
-
-	if(order <= 12) {
-		if(order > 8) {
-			if(order > 10) {
-				if(order == 12) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
-					q8  = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
-					q9  = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
-					q10 = _mm256_set1_epi32(0xffff & qlp_coeff[10]);
-					q11 = _mm256_set1_epi32(0xffff & qlp_coeff[11]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q11, _mm256_loadu_si256((const __m256i*)(data+i-12)));
-						mull = _mm256_madd_epi16(q10, _mm256_loadu_si256((const __m256i*)(data+i-11))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 11 */
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
-					q8  = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
-					q9  = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
-					q10 = _mm256_set1_epi32(0xffff & qlp_coeff[10]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q10, _mm256_loadu_si256((const __m256i*)(data+i-11)));
-						mull = _mm256_madd_epi16(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 10) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
-					q8  = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
-					q9  = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10)));
-						mull = _mm256_madd_epi16(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 9 */
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
-					q8  = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9 )));
-						mull = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		else if(order > 4) {
-			if(order > 6) {
-				if(order == 8) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 )));
-						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 7 */
-					__m256i q0, q1, q2, q3, q4, q5, q6;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 )));
-						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 6) {
-					__m256i q0, q1, q2, q3, q4, q5;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 )));
-						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 5 */
-					__m256i q0, q1, q2, q3, q4;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 )));
-						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		else {
-			if(order > 2) {
-				if(order == 4) {
-					__m256i q0, q1, q2, q3;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 )));
-						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 3 */
-					__m256i q0, q1, q2;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 )));
-						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 2) {
-					__m256i q0, q1;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 )));
-						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 1 */
-					__m256i q0;
-					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ;
-						summ = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 )));
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		for(; i < (int)data_len; i++) {
-			sum = 0;
-			switch(order) {
-				case 12: sum += qlp_coeff[11] * data[i-12];
-				case 11: sum += qlp_coeff[10] * data[i-11];
-				case 10: sum += qlp_coeff[ 9] * data[i-10];
-				case 9:  sum += qlp_coeff[ 8] * data[i- 9];
-				case 8:  sum += qlp_coeff[ 7] * data[i- 8];
-				case 7:  sum += qlp_coeff[ 6] * data[i- 7];
-				case 6:  sum += qlp_coeff[ 5] * data[i- 6];
-				case 5:  sum += qlp_coeff[ 4] * data[i- 5];
-				case 4:  sum += qlp_coeff[ 3] * data[i- 4];
-				case 3:  sum += qlp_coeff[ 2] * data[i- 3];
-				case 2:  sum += qlp_coeff[ 1] * data[i- 2];
-				case 1:  sum += qlp_coeff[ 0] * data[i- 1];
-			}
-			residual[i] = data[i] - (sum >> 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);
-		}
-	}
-	_mm256_zeroupper();
-}
-
-FLAC__SSE_TARGET("avx2")
-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[])
-{
-	int i;
-	FLAC__int32 sum;
-	__m128i cnt = _mm_cvtsi32_si128(lp_quantization);
-
-	FLAC__ASSERT(order > 0);
-	FLAC__ASSERT(order <= 32);
-
-	if(order <= 12) {
-		if(order > 8) {
-			if(order > 10) {
-				if(order == 12) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
-					q8  = _mm256_set1_epi32(qlp_coeff[8 ]);
-					q9  = _mm256_set1_epi32(qlp_coeff[9 ]);
-					q10 = _mm256_set1_epi32(qlp_coeff[10]);
-					q11 = _mm256_set1_epi32(qlp_coeff[11]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q11, _mm256_loadu_si256((const __m256i*)(data+i-12)));
-						mull = _mm256_mullo_epi32(q10, _mm256_loadu_si256((const __m256i*)(data+i-11))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 11 */
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
-					q8  = _mm256_set1_epi32(qlp_coeff[8 ]);
-					q9  = _mm256_set1_epi32(qlp_coeff[9 ]);
-					q10 = _mm256_set1_epi32(qlp_coeff[10]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q10, _mm256_loadu_si256((const __m256i*)(data+i-11)));
-						mull = _mm256_mullo_epi32(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 10) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
-					q8  = _mm256_set1_epi32(qlp_coeff[8 ]);
-					q9  = _mm256_set1_epi32(qlp_coeff[9 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10)));
-						mull = _mm256_mullo_epi32(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 9 */
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
-					q8  = _mm256_set1_epi32(qlp_coeff[8 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9)));
-						mull = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		else if(order > 4) {
-			if(order > 6) {
-				if(order == 8) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
-					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));
-						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 7 */
-					__m256i q0, q1, q2, q3, q4, q5, q6;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
-					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));
-						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 6) {
-					__m256i q0, q1, q2, q3, q4, q5;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
-					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));
-						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 5 */
-					__m256i q0, q1, q2, q3, q4;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));
-						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		else {
-			if(order > 2) {
-				if(order == 4) {
-					__m256i q0, q1, q2, q3;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));
-						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 3 */
-					__m256i q0, q1, q2;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));
-						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 2) {
-					__m256i q0, q1;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ, mull;
-						summ = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));
-						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 1 */
-					__m256i q0;
-					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
-
-					for(i = 0; i < (int)data_len-7; i+=8) {
-						__m256i summ;
-						summ = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));
-						summ = _mm256_sra_epi32(summ, cnt);
-						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		for(; i < (int)data_len; i++) {
-			sum = 0;
-			switch(order) {
-				case 12: sum += qlp_coeff[11] * data[i-12];
-				case 11: sum += qlp_coeff[10] * data[i-11];
-				case 10: sum += qlp_coeff[ 9] * data[i-10];
-				case 9:  sum += qlp_coeff[ 8] * data[i- 9];
-				case 8:  sum += qlp_coeff[ 7] * data[i- 8];
-				case 7:  sum += qlp_coeff[ 6] * data[i- 7];
-				case 6:  sum += qlp_coeff[ 5] * data[i- 6];
-				case 5:  sum += qlp_coeff[ 4] * data[i- 5];
-				case 4:  sum += qlp_coeff[ 3] * data[i- 4];
-				case 3:  sum += qlp_coeff[ 2] * data[i- 3];
-				case 2:  sum += qlp_coeff[ 1] * data[i- 2];
-				case 1:  sum += qlp_coeff[ 0] * data[i- 1];
-			}
-			residual[i] = data[i] - (sum >> 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);
-		}
-	}
-	_mm256_zeroupper();
-}
-
-static FLAC__int32 pack_arr[8] = { 0, 2, 4, 6, 1, 3, 5, 7 };
-
-FLAC__SSE_TARGET("avx2")
-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[])
-{
-	int i;
-	FLAC__int64 sum;
-	__m128i cnt = _mm_cvtsi32_si128(lp_quantization);
-	__m256i pack = _mm256_loadu_si256((const __m256i *)pack_arr);
-
-	FLAC__ASSERT(order > 0);
-	FLAC__ASSERT(order <= 32);
-	FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm256_sra_epi64() so we have to use _mm256_srl_epi64() */
-
-	if(order <= 12) {
-		if(order > 8) {
-			if(order > 10) {
-				if(order == 12) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
-					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
-					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
-					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
-					q8  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
-					q9  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
-					q10 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[10]));
-					q11 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[11]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q11, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-12))));
-						mull = _mm256_mul_epi32(q10, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-11)))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q9,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-10)))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q8,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-				else { /* order == 11 */
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
-					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
-					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
-					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
-					q8  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
-					q9  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
-					q10 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[10]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q10, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-11))));
-						mull = _mm256_mul_epi32(q9,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-10)))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q8,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-			}
-			else {
-				if(order == 10) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
-					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
-					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
-					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
-					q8  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
-					q9  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q9,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-10))));
-						mull = _mm256_mul_epi32(q8,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-				else { /* order == 9 */
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
-					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
-					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
-					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
-					q8  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q8,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-9 ))));
-						mull = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-			}
-		}
-		else if(order > 4) {
-			if(order > 6) {
-				if(order == 8) {
-					__m256i q0, q1, q2, q3, q4, q5, q6, q7;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
-					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
-					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
-					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 ))));
-						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-				else { /* order == 7 */
-					__m256i q0, q1, q2, q3, q4, q5, q6;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
-					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
-					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 ))));
-						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-			}
-			else {
-				if(order == 6) {
-					__m256i q0, q1, q2, q3, q4, q5;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
-					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 ))));
-						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-				else { /* order == 5 */
-					__m256i q0, q1, q2, q3, q4;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 ))));
-						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-			}
-		}
-		else {
-			if(order > 2) {
-				if(order == 4) {
-					__m256i q0, q1, q2, q3;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 ))));
-						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-				else { /* order == 3 */
-					__m256i q0, q1, q2;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 ))));
-						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-			}
-			else {
-				if(order == 2) {
-					__m256i q0, q1;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ, mull;
-						summ = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 ))));
-						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-				else { /* order == 1 */
-					__m256i q0;
-					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m256i summ;
-						summ = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 ))));
-						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
-					}
-				}
-			}
-		}
-		for(; i < (int)data_len; i++) {
-			sum = 0;
-			switch(order) {
-				case 12: sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
-				case 11: sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
-				case 10: sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
-				case 9:  sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
-				case 8:  sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
-				case 7:  sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
-				case 6:  sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
-				case 5:  sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
-				case 4:  sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
-				case 3:  sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
-				case 2:  sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
-				case 1:  sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
-			}
-			residual[i] = data[i] - (FLAC__int32)(sum >> 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);
-		}
-	}
-	_mm256_zeroupper();
-}
-
-#endif /* FLAC__AVX2_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
-#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/libFLAC/lpc_intrin_sse.c b/libFLAC/lpc_intrin_sse.c
deleted file mode 100644
index 430e73f..0000000
--- a/libFLAC/lpc_intrin_sse.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#include "private/lpc.h"
-#ifdef FLAC__SSE_SUPPORTED
-#include "FLAC/assert.h"
-#include "FLAC/format.h"
-
-#include <xmmintrin.h> /* SSE */
-
-/*   new routines: more unaligned loads, less shuffle
- *   old routines: less unaligned loads, more shuffle
- *   these *_old routines are equivalent to the ASM routines in ia32/lpc_asm.nasm
- */
-
-/* new routines: faster on current Intel (starting from Core i aka Nehalem) and all AMD CPUs */
-
-FLAC__SSE_TARGET("sse")
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
-{
-	int i;
-	int limit = data_len - 4;
-	__m128 sum0;
-
-	(void) lag;
-	FLAC__ASSERT(lag <= 4);
-	FLAC__ASSERT(lag <= data_len);
-
-	sum0 = _mm_setzero_ps();
-
-	for(i = 0; i <= limit; i++) {
-		__m128 d, d0;
-		d0 = _mm_loadu_ps(data+i);
-		d = d0; d = _mm_shuffle_ps(d, d, 0);
-		sum0 = _mm_add_ps(sum0, _mm_mul_ps(d0, d));
-	}
-
-	{
-		__m128 d0 = _mm_setzero_ps();
-		limit++; if(limit < 0) limit = 0;
-
-		for(i = data_len-1; i >= limit; i--) {
-			__m128 d;
-			d = _mm_load_ss(data+i); d = _mm_shuffle_ps(d, d, 0);
-			d0 = _mm_shuffle_ps(d0, d0, _MM_SHUFFLE(2,1,0,3));
-			d0 = _mm_move_ss(d0, d);
-			sum0 = _mm_add_ps(sum0, _mm_mul_ps(d, d0));
-		}
-	}
-
-	_mm_storeu_ps(autoc,   sum0);
-}
-
-FLAC__SSE_TARGET("sse")
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
-{
-	int i;
-	int limit = data_len - 8;
-	__m128 sum0, sum1;
-
-	(void) lag;
-	FLAC__ASSERT(lag <= 8);
-	FLAC__ASSERT(lag <= data_len);
-
-	sum0 = _mm_setzero_ps();
-	sum1 = _mm_setzero_ps();
-
-	for(i = 0; i <= limit; i++) {
-		__m128 d, d0, d1;
-		d0 = _mm_loadu_ps(data+i);
-		d1 = _mm_loadu_ps(data+i+4);
-		d = d0; d = _mm_shuffle_ps(d, d, 0);
-		sum0 = _mm_add_ps(sum0, _mm_mul_ps(d0, d));
-		sum1 = _mm_add_ps(sum1, _mm_mul_ps(d1, d));
-	}
-
-	{
-		__m128 d0 = _mm_setzero_ps();
-		__m128 d1 = _mm_setzero_ps();
-		limit++; if(limit < 0) limit = 0;
-
-		for(i = data_len-1; i >= limit; i--) {
-			__m128 d;
-			d = _mm_load_ss(data+i); d = _mm_shuffle_ps(d, d, 0);
-			d1 = _mm_shuffle_ps(d1, d1, _MM_SHUFFLE(2,1,0,3));
-			d0 = _mm_shuffle_ps(d0, d0, _MM_SHUFFLE(2,1,0,3));
-			d1 = _mm_move_ss(d1, d0);
-			d0 = _mm_move_ss(d0, d);
-			sum1 = _mm_add_ps(sum1, _mm_mul_ps(d, d1));
-			sum0 = _mm_add_ps(sum0, _mm_mul_ps(d, d0));
-		}
-	}
-
-	_mm_storeu_ps(autoc,   sum0);
-	_mm_storeu_ps(autoc+4, sum1);
-}
-
-FLAC__SSE_TARGET("sse")
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
-{
-	int i;
-	int limit = data_len - 12;
-	__m128 sum0, sum1, sum2;
-
-	(void) lag;
-	FLAC__ASSERT(lag <= 12);
-	FLAC__ASSERT(lag <= data_len);
-
-	sum0 = _mm_setzero_ps();
-	sum1 = _mm_setzero_ps();
-	sum2 = _mm_setzero_ps();
-
-	for(i = 0; i <= limit; i++) {
-		__m128 d, d0, d1, d2;
-		d0 = _mm_loadu_ps(data+i);
-		d1 = _mm_loadu_ps(data+i+4);
-		d2 = _mm_loadu_ps(data+i+8);
-		d = d0; d = _mm_shuffle_ps(d, d, 0);
-		sum0 = _mm_add_ps(sum0, _mm_mul_ps(d0, d));
-		sum1 = _mm_add_ps(sum1, _mm_mul_ps(d1, d));
-		sum2 = _mm_add_ps(sum2, _mm_mul_ps(d2, d));
-	}
-
-	{
-		__m128 d0 = _mm_setzero_ps();
-		__m128 d1 = _mm_setzero_ps();
-		__m128 d2 = _mm_setzero_ps();
-		limit++; if(limit < 0) limit = 0;
-
-		for(i = data_len-1; i >= limit; i--) {
-			__m128 d;
-			d = _mm_load_ss(data+i); d = _mm_shuffle_ps(d, d, 0);
-			d2 = _mm_shuffle_ps(d2, d2, _MM_SHUFFLE(2,1,0,3));
-			d1 = _mm_shuffle_ps(d1, d1, _MM_SHUFFLE(2,1,0,3));
-			d0 = _mm_shuffle_ps(d0, d0, _MM_SHUFFLE(2,1,0,3));
-			d2 = _mm_move_ss(d2, d1);
-			d1 = _mm_move_ss(d1, d0);
-			d0 = _mm_move_ss(d0, d);
-			sum2 = _mm_add_ps(sum2, _mm_mul_ps(d, d2));
-			sum1 = _mm_add_ps(sum1, _mm_mul_ps(d, d1));
-			sum0 = _mm_add_ps(sum0, _mm_mul_ps(d, d0));
-		}
-	}
-
-	_mm_storeu_ps(autoc,   sum0);
-	_mm_storeu_ps(autoc+4, sum1);
-	_mm_storeu_ps(autoc+8, sum2);
-}
-
-FLAC__SSE_TARGET("sse")
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
-{
-	int i;
-	int limit = data_len - 16;
-	__m128 sum0, sum1, sum2, sum3;
-
-	(void) lag;
-	FLAC__ASSERT(lag <= 16);
-	FLAC__ASSERT(lag <= data_len);
-
-	sum0 = _mm_setzero_ps();
-	sum1 = _mm_setzero_ps();
-	sum2 = _mm_setzero_ps();
-	sum3 = _mm_setzero_ps();
-
-	for(i = 0; i <= limit; i++) {
-		__m128 d, d0, d1, d2, d3;
-		d0 = _mm_loadu_ps(data+i);
-		d1 = _mm_loadu_ps(data+i+4);
-		d2 = _mm_loadu_ps(data+i+8);
-		d3 = _mm_loadu_ps(data+i+12);
-		d = d0; d = _mm_shuffle_ps(d, d, 0);
-		sum0 = _mm_add_ps(sum0, _mm_mul_ps(d0, d));
-		sum1 = _mm_add_ps(sum1, _mm_mul_ps(d1, d));
-		sum2 = _mm_add_ps(sum2, _mm_mul_ps(d2, d));
-		sum3 = _mm_add_ps(sum3, _mm_mul_ps(d3, d));
-	}
-
-	{
-		__m128 d0 = _mm_setzero_ps();
-		__m128 d1 = _mm_setzero_ps();
-		__m128 d2 = _mm_setzero_ps();
-		__m128 d3 = _mm_setzero_ps();
-		limit++; if(limit < 0) limit = 0;
-
-		for(i = data_len-1; i >= limit; i--) {
-			__m128 d;
-			d = _mm_load_ss(data+i); d = _mm_shuffle_ps(d, d, 0);
-			d3 = _mm_shuffle_ps(d3, d3, _MM_SHUFFLE(2,1,0,3));
-			d2 = _mm_shuffle_ps(d2, d2, _MM_SHUFFLE(2,1,0,3));
-			d1 = _mm_shuffle_ps(d1, d1, _MM_SHUFFLE(2,1,0,3));
-			d0 = _mm_shuffle_ps(d0, d0, _MM_SHUFFLE(2,1,0,3));
-			d3 = _mm_move_ss(d3, d2);
-			d2 = _mm_move_ss(d2, d1);
-			d1 = _mm_move_ss(d1, d0);
-			d0 = _mm_move_ss(d0, d);
-			sum3 = _mm_add_ps(sum3, _mm_mul_ps(d, d3));
-			sum2 = _mm_add_ps(sum2, _mm_mul_ps(d, d2));
-			sum1 = _mm_add_ps(sum1, _mm_mul_ps(d, d1));
-			sum0 = _mm_add_ps(sum0, _mm_mul_ps(d, d0));
-		}
-	}
-
-	_mm_storeu_ps(autoc,   sum0);
-	_mm_storeu_ps(autoc+4, sum1);
-	_mm_storeu_ps(autoc+8, sum2);
-	_mm_storeu_ps(autoc+12,sum3);
-}
-
-/* old routines: faster on older Intel CPUs (up to Core 2) */
-
-FLAC__SSE_TARGET("sse")
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
-{
-	__m128 xmm0, xmm2, xmm5;
-
-	(void) lag;
-	FLAC__ASSERT(lag > 0);
-	FLAC__ASSERT(lag <= 4);
-	FLAC__ASSERT(lag <= data_len);
-	FLAC__ASSERT(data_len > 0);
-
-	xmm5 = _mm_setzero_ps();
-
-	xmm0 = _mm_load_ss(data++);
-	xmm2 = xmm0;
-	xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0);
-
-	xmm0 = _mm_mul_ps(xmm0, xmm2);
-	xmm5 = _mm_add_ps(xmm5, xmm0);
-
-	data_len--;
-
-	while(data_len)
-	{
-		xmm0 = _mm_load1_ps(data++);
-
-		xmm2 = _mm_shuffle_ps(xmm2, xmm2, _MM_SHUFFLE(2,1,0,3));
-		xmm2 = _mm_move_ss(xmm2, xmm0);
-		xmm0 = _mm_mul_ps(xmm0, xmm2);
-		xmm5 = _mm_add_ps(xmm5, xmm0);
-
-		data_len--;
-	}
-
-	_mm_storeu_ps(autoc, xmm5);
-}
-
-FLAC__SSE_TARGET("sse")
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
-{
-	__m128 xmm0, xmm1, xmm2, xmm3, xmm5, xmm6;
-
-	(void) lag;
-	FLAC__ASSERT(lag > 0);
-	FLAC__ASSERT(lag <= 8);
-	FLAC__ASSERT(lag <= data_len);
-	FLAC__ASSERT(data_len > 0);
-
-	xmm5 = _mm_setzero_ps();
-	xmm6 = _mm_setzero_ps();
-
-	xmm0 = _mm_load_ss(data++);
-	xmm2 = xmm0;
-	xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0);
-	xmm3 = _mm_setzero_ps();
-
-	xmm0 = _mm_mul_ps(xmm0, xmm2);
-	xmm5 = _mm_add_ps(xmm5, xmm0);
-
-	data_len--;
-
-	while(data_len)
-	{
-		xmm0 = _mm_load1_ps(data++);
-
-		xmm2 = _mm_shuffle_ps(xmm2, xmm2, _MM_SHUFFLE(2,1,0,3));
-		xmm3 = _mm_shuffle_ps(xmm3, xmm3, _MM_SHUFFLE(2,1,0,3));
-		xmm3 = _mm_move_ss(xmm3, xmm2);
-		xmm2 = _mm_move_ss(xmm2, xmm0);
-
-		xmm1 = xmm0;
-		xmm1 = _mm_mul_ps(xmm1, xmm3);
-		xmm0 = _mm_mul_ps(xmm0, xmm2);
-		xmm6 = _mm_add_ps(xmm6, xmm1);
-		xmm5 = _mm_add_ps(xmm5, xmm0);
-
-		data_len--;
-	}
-
-	_mm_storeu_ps(autoc,   xmm5);
-	_mm_storeu_ps(autoc+4, xmm6);
-}
-
-FLAC__SSE_TARGET("sse")
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
-{
-	__m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
-
-	(void) lag;
-	FLAC__ASSERT(lag > 0);
-	FLAC__ASSERT(lag <= 12);
-	FLAC__ASSERT(lag <= data_len);
-	FLAC__ASSERT(data_len > 0);
-
-	xmm5 = _mm_setzero_ps();
-	xmm6 = _mm_setzero_ps();
-	xmm7 = _mm_setzero_ps();
-
-	xmm0 = _mm_load_ss(data++);
-	xmm2 = xmm0;
-	xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0);
-	xmm3 = _mm_setzero_ps();
-	xmm4 = _mm_setzero_ps();
-
-	xmm0 = _mm_mul_ps(xmm0, xmm2);
-	xmm5 = _mm_add_ps(xmm5, xmm0);
-
-	data_len--;
-
-	while(data_len)
-	{
-		xmm0 = _mm_load1_ps(data++);
-
-		xmm2 = _mm_shuffle_ps(xmm2, xmm2, _MM_SHUFFLE(2,1,0,3));
-		xmm3 = _mm_shuffle_ps(xmm3, xmm3, _MM_SHUFFLE(2,1,0,3));
-		xmm4 = _mm_shuffle_ps(xmm4, xmm4, _MM_SHUFFLE(2,1,0,3));
-		xmm4 = _mm_move_ss(xmm4, xmm3);
-		xmm3 = _mm_move_ss(xmm3, xmm2);
-		xmm2 = _mm_move_ss(xmm2, xmm0);
-
-		xmm1 = xmm0;
-		xmm1 = _mm_mul_ps(xmm1, xmm2);
-		xmm5 = _mm_add_ps(xmm5, xmm1);
-		xmm1 = xmm0;
-		xmm1 = _mm_mul_ps(xmm1, xmm3);
-		xmm6 = _mm_add_ps(xmm6, xmm1);
-		xmm0 = _mm_mul_ps(xmm0, xmm4);
-		xmm7 = _mm_add_ps(xmm7, xmm0);
-
-		data_len--;
-	}
-
-	_mm_storeu_ps(autoc,   xmm5);
-	_mm_storeu_ps(autoc+4, xmm6);
-	_mm_storeu_ps(autoc+8, xmm7);
-}
-
-FLAC__SSE_TARGET("sse")
-void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
-{
-	__m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9;
-
-	(void) lag;
-	FLAC__ASSERT(lag > 0);
-	FLAC__ASSERT(lag <= 16);
-	FLAC__ASSERT(lag <= data_len);
-	FLAC__ASSERT(data_len > 0);
-
-	xmm6 = _mm_setzero_ps();
-	xmm7 = _mm_setzero_ps();
-	xmm8 = _mm_setzero_ps();
-	xmm9 = _mm_setzero_ps();
-
-	xmm0 = _mm_load_ss(data++);
-	xmm2 = xmm0;
-	xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0);
-	xmm3 = _mm_setzero_ps();
-	xmm4 = _mm_setzero_ps();
-	xmm5 = _mm_setzero_ps();
-
-	xmm0 = _mm_mul_ps(xmm0, xmm2);
-	xmm6 = _mm_add_ps(xmm6, xmm0);
-
-	data_len--;
-
-	while(data_len)
-	{
-		xmm0 = _mm_load1_ps(data++);
-
-		/* shift xmm5:xmm4:xmm3:xmm2 left by one float */
-		xmm5 = _mm_shuffle_ps(xmm5, xmm5, _MM_SHUFFLE(2,1,0,3));
-		xmm4 = _mm_shuffle_ps(xmm4, xmm4, _MM_SHUFFLE(2,1,0,3));
-		xmm3 = _mm_shuffle_ps(xmm3, xmm3, _MM_SHUFFLE(2,1,0,3));
-		xmm2 = _mm_shuffle_ps(xmm2, xmm2, _MM_SHUFFLE(2,1,0,3));
-		xmm5 = _mm_move_ss(xmm5, xmm4);
-		xmm4 = _mm_move_ss(xmm4, xmm3);
-		xmm3 = _mm_move_ss(xmm3, xmm2);
-		xmm2 = _mm_move_ss(xmm2, xmm0);
-
-		/* xmm9|xmm8|xmm7|xmm6 += xmm0|xmm0|xmm0|xmm0 * xmm5|xmm4|xmm3|xmm2 */
-		xmm1 = xmm0;
-		xmm1 = _mm_mul_ps(xmm1, xmm5);
-		xmm9 = _mm_add_ps(xmm9, xmm1);
-		xmm1 = xmm0;
-		xmm1 = _mm_mul_ps(xmm1, xmm4);
-		xmm8 = _mm_add_ps(xmm8, xmm1);
-		xmm1 = xmm0;
-		xmm1 = _mm_mul_ps(xmm1, xmm3);
-		xmm7 = _mm_add_ps(xmm7, xmm1);
-		xmm0 = _mm_mul_ps(xmm0, xmm2);
-		xmm6 = _mm_add_ps(xmm6, xmm0);
-
-		data_len--;
-	}
-
-	_mm_storeu_ps(autoc,   xmm6);
-	_mm_storeu_ps(autoc+4, xmm7);
-	_mm_storeu_ps(autoc+8, xmm8);
-	_mm_storeu_ps(autoc+12,xmm9);
-}
-
-#endif /* FLAC__SSE_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
-#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/libFLAC/lpc_intrin_sse2.c b/libFLAC/lpc_intrin_sse2.c
deleted file mode 100644
index 1383394..0000000
--- a/libFLAC/lpc_intrin_sse2.c
+++ /dev/null
@@ -1,1090 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#include "private/lpc.h"
-#ifdef FLAC__SSE2_SUPPORTED
-
-#include "FLAC/assert.h"
-#include "FLAC/format.h"
-
-#include <emmintrin.h> /* SSE2 */
-
-#define RESIDUAL16_RESULT(xmmN) curr = *data++; *residual++ = curr - (_mm_cvtsi128_si32(xmmN) >> lp_quantization);
-#define     DATA16_RESULT(xmmN) curr = *residual++ + (_mm_cvtsi128_si32(xmmN) >> lp_quantization); *data++ = curr;
-
-#define RESIDUAL32_RESULT(xmmN) residual[i] = data[i] - (_mm_cvtsi128_si32(xmmN) >> lp_quantization);
-#define     DATA32_RESULT(xmmN) data[i] = residual[i] + (_mm_cvtsi128_si32(xmmN) >> lp_quantization);
-
-FLAC__SSE_TARGET("sse2")
-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[])
-{
-	int i;
-	FLAC__int32 sum;
-	__m128i cnt = _mm_cvtsi32_si128(lp_quantization);
-
-	FLAC__ASSERT(order > 0);
-	FLAC__ASSERT(order <= 32);
-
-	if(order <= 12) {
-		if(order > 8) {
-			if(order > 10) {
-				if(order == 12) {
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-					q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
-					q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
-					q10 = _mm_cvtsi32_si128(0xffff & qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
-					q11 = _mm_cvtsi32_si128(0xffff & qlp_coeff[11]); q11 = _mm_shuffle_epi32(q11, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q11, _mm_loadu_si128((const __m128i*)(data+i-12)));
-						mull = _mm_madd_epi16(q10, _mm_loadu_si128((const __m128i*)(data+i-11))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 11 */
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-					q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
-					q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
-					q10 = _mm_cvtsi32_si128(0xffff & qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q10, _mm_loadu_si128((const __m128i*)(data+i-11)));
-						mull = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 10) {
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-					q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
-					q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(data+i-10)));
-						mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 9 */
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-					q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(data+i-9)));
-						mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		else if(order > 4) {
-			if(order > 6) {
-				if(order == 8) {
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8)));
-						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 7 */
-					__m128i q0, q1, q2, q3, q4, q5, q6;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7)));
-						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 6) {
-					__m128i q0, q1, q2, q3, q4, q5;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6)));
-						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 5 */
-					__m128i q0, q1, q2, q3, q4;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5)));
-						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		else {
-			if(order > 2) {
-				if(order == 4) {
-					__m128i q0, q1, q2, q3;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4)));
-						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 3 */
-					__m128i q0, q1, q2;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3)));
-						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 2) {
-					__m128i q0, q1;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2)));
-						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 1 */
-					__m128i q0;
-					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ;
-						summ = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1)));
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		for(; i < (int)data_len; i++) {
-			sum = 0;
-			switch(order) {
-				case 12: sum += qlp_coeff[11] * data[i-12];
-				case 11: sum += qlp_coeff[10] * data[i-11];
-				case 10: sum += qlp_coeff[ 9] * data[i-10];
-				case 9:  sum += qlp_coeff[ 8] * data[i- 9];
-				case 8:  sum += qlp_coeff[ 7] * data[i- 8];
-				case 7:  sum += qlp_coeff[ 6] * data[i- 7];
-				case 6:  sum += qlp_coeff[ 5] * data[i- 6];
-				case 5:  sum += qlp_coeff[ 4] * data[i- 5];
-				case 4:  sum += qlp_coeff[ 3] * data[i- 4];
-				case 3:  sum += qlp_coeff[ 2] * data[i- 3];
-				case 2:  sum += qlp_coeff[ 1] * data[i- 2];
-				case 1:  sum += qlp_coeff[ 0] * data[i- 1];
-			}
-			residual[i] = data[i] - (sum >> 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);
-		}
-	}
-}
-
-FLAC__SSE_TARGET("sse2")
-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[])
-{
-	int i;
-
-	FLAC__ASSERT(order > 0);
-	FLAC__ASSERT(order <= 32);
-
-	if(order <= 12) {
-		if(order > 8) { /* order == 9, 10, 11, 12 */
-			if(order > 10) { /* order == 11, 12 */
-				if(order == 12) {
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));  // 0  0  q[1]  q[0]
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));  // 0  0  q[3]  q[2]
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));  // 0  0  q[5]  q[4]
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));  // 0  0  q[7]  q[6]
-					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));  // 0  0  q[9]  q[8]
-					xmm5 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+10)); // 0  0  q[11] q[10]
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); // 0  q[1]  0  q[0]
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); // 0  q[3]  0  q[2]
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); // 0  q[5]  0  q[4]
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); // 0  q[7]  0  q[6]
-					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); // 0  q[9]  0  q[8]
-					xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(3,1,2,0)); // 0  q[11] 0  q[10]
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum += qlp_coeff[11] * data[i-12];
-						//sum += qlp_coeff[10] * data[i-11];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-12));  // 0   0        d[i-11]  d[i-12]
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); // 0  d[i-12]   0        d[i-11]
-						xmm7 = _mm_mul_epu32(xmm7, xmm5); /* we use _unsigned_ multiplication and discard high dword of the result values */
-
-						//sum += qlp_coeff[9] * data[i-10];
-						//sum += qlp_coeff[8] * data[i-9];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-10));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm4);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[7] * data[i-8];
-						//sum += qlp_coeff[6] * data[i-7];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm3);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[5] * data[i-6];
-						//sum += qlp_coeff[4] * data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm2);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm1);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-				else { /* order == 11 */
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
-					xmm5 = _mm_cvtsi32_si128(qlp_coeff[10]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
-					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[10] * data[i-11];
-						xmm7 = _mm_cvtsi32_si128(data[i-11]);
-						xmm7 = _mm_mul_epu32(xmm7, xmm5);
-
-						//sum += qlp_coeff[9] * data[i-10];
-						//sum += qlp_coeff[8] * data[i-9];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-10));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm4);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[7] * data[i-8];
-						//sum += qlp_coeff[6] * data[i-7];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm3);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[5] * data[i-6];
-						//sum += qlp_coeff[4] * data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm2);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm1);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-			}
-			else { /* order == 9, 10 */
-				if(order == 10) {
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
-					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum += qlp_coeff[9] * data[i-10];
-						//sum += qlp_coeff[8] * data[i-9];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-10));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epu32(xmm7, xmm4);
-
-						//sum += qlp_coeff[7] * data[i-8];
-						//sum += qlp_coeff[6] * data[i-7];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm3);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[5] * data[i-6];
-						//sum += qlp_coeff[4] * data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm2);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm1);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-				else { /* order == 9 */
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-					xmm4 = _mm_cvtsi32_si128(qlp_coeff[8]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[8] * data[i-9];
-						xmm7 = _mm_cvtsi32_si128(data[i-9]);
-						xmm7 = _mm_mul_epu32(xmm7, xmm4);
-
-						//sum += qlp_coeff[7] * data[i-8];
-						//sum += qlp_coeff[6] * data[i-7];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm3);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[5] * data[i-6];
-						//sum += qlp_coeff[4] * data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm2);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm1);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-			}
-		}
-		else if(order > 4) { /* order == 5, 6, 7, 8 */
-			if(order > 6) { /* order == 7, 8 */
-				if(order == 8) {
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum += qlp_coeff[7] * data[i-8];
-						//sum += qlp_coeff[6] * data[i-7];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epu32(xmm7, xmm3);
-
-						//sum += qlp_coeff[5] * data[i-6];
-						//sum += qlp_coeff[4] * data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm2);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm1);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-				else { /* order == 7 */
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_cvtsi32_si128(qlp_coeff[6]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[6] * data[i-7];
-						xmm7 = _mm_cvtsi32_si128(data[i-7]);
-						xmm7 = _mm_mul_epu32(xmm7, xmm3);
-
-						//sum += qlp_coeff[5] * data[i-6];
-						//sum += qlp_coeff[4] * data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm2);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm1);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-			}
-			else { /* order == 5, 6 */
-				if(order == 6) {
-					__m128i xmm0, xmm1, xmm2, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum += qlp_coeff[5] * data[i-6];
-						//sum += qlp_coeff[4] * data[i-5];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epu32(xmm7, xmm2);
-
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm1);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-				else { /* order == 5 */
-					__m128i xmm0, xmm1, xmm2, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_cvtsi32_si128(qlp_coeff[4]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[4] * data[i-5];
-						xmm7 = _mm_cvtsi32_si128(data[i-5]);
-						xmm7 = _mm_mul_epu32(xmm7, xmm2);
-
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm1);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-			}
-		}
-		else { /* order == 1, 2, 3, 4 */
-			if(order > 2) { /* order == 3, 4 */
-				if(order == 4) {
-					__m128i xmm0, xmm1, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum += qlp_coeff[3] * data[i-4];
-						//sum += qlp_coeff[2] * data[i-3];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epu32(xmm7, xmm1);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-				else { /* order == 3 */
-					__m128i xmm0, xmm1, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_cvtsi32_si128(qlp_coeff[2]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[2] * data[i-3];
-						xmm7 = _mm_cvtsi32_si128(data[i-3]);
-						xmm7 = _mm_mul_epu32(xmm7, xmm1);
-
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epu32(xmm6, xmm0);
-						xmm7 = _mm_add_epi32(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-			}
-			else { /* order == 1, 2 */
-				if(order == 2) {
-					__m128i xmm0, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum += qlp_coeff[1] * data[i-2];
-						//sum += qlp_coeff[0] * data[i-1];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epu32(xmm7, xmm0);
-
-						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL32_RESULT(xmm7);
-					}
-				}
-				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 */
-		FLAC__int32 sum;
-		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);
-		}
-	}
-}
-
-#if defined FLAC__CPU_IA32 && !defined FLAC__HAS_NASM /* unused for x64; not better than MMX asm */
-
-FLAC__SSE_TARGET("sse2")
-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[])
-{
-	if (order < 8 || order > 12) {
-		FLAC__lpc_restore_signal(residual, data_len, qlp_coeff, order, lp_quantization, data);
-		return;
-	}
-	if (data_len == 0)
-		return;
-
-	FLAC__ASSERT(order >= 8);
-	FLAC__ASSERT(order <= 12);
-
-	if(order > 8) { /* order == 9, 10, 11, 12 */
-		FLAC__int32 curr;
-		__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
-		xmm0 = _mm_loadu_si128((const __m128i*)(qlp_coeff+0));
-		xmm6 = _mm_loadu_si128((const __m128i*)(qlp_coeff+4));
-		xmm1 = _mm_loadu_si128((const __m128i*)(qlp_coeff+8)); /* read 0 to 3 uninitialized coeffs... */
-		switch(order)                                          /* ...and zero them out */
-		{
-		case 9:
-			xmm1 = _mm_slli_si128(xmm1, 12); xmm1 = _mm_srli_si128(xmm1, 12); break;
-		case 10:
-			xmm1 = _mm_slli_si128(xmm1, 8); xmm1 = _mm_srli_si128(xmm1, 8); break;
-		case 11:
-			xmm1 = _mm_slli_si128(xmm1, 4); xmm1 = _mm_srli_si128(xmm1, 4); break;
-		}
-		xmm2 = _mm_setzero_si128();
-		xmm0 = _mm_packs_epi32(xmm0, xmm6);
-		xmm1 = _mm_packs_epi32(xmm1, xmm2);
-
-		xmm4 = _mm_loadu_si128((const __m128i*)(data-12));
-		xmm5 = _mm_loadu_si128((const __m128i*)(data-8));
-		xmm3 = _mm_loadu_si128((const __m128i*)(data-4));
-		xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(0,1,2,3));
-		xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(0,1,2,3));
-		xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(0,1,2,3));
-		xmm4 = _mm_packs_epi32(xmm4, xmm2);
-		xmm3 = _mm_packs_epi32(xmm3, xmm5);
-
-		xmm7 = _mm_slli_si128(xmm1, 2);
-		xmm7 = _mm_or_si128(xmm7, _mm_srli_si128(xmm0, 14));
-		xmm2 = _mm_slli_si128(xmm0, 2);
-
-		/* xmm0, xmm1: qlp_coeff
-			xmm2, xmm7: qlp_coeff << 16 bit
-			xmm3, xmm4: data */
-
-		xmm5 = _mm_madd_epi16(xmm4, xmm1);
-		xmm6 = _mm_madd_epi16(xmm3, xmm0);
-		xmm6 = _mm_add_epi32(xmm6, xmm5);
-		xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 8));
-		xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 4));
-
-		DATA16_RESULT(xmm6);
-
-		data_len--;
-
-		if(data_len % 2) {
-			xmm6 = _mm_srli_si128(xmm3, 14);
-			xmm4 = _mm_slli_si128(xmm4, 2);
-			xmm3 = _mm_slli_si128(xmm3, 2);
-			xmm4 = _mm_or_si128(xmm4, xmm6);
-			xmm3 = _mm_insert_epi16(xmm3, curr, 0);
-
-			xmm5 = _mm_madd_epi16(xmm4, xmm1);
-			xmm6 = _mm_madd_epi16(xmm3, xmm0);
-			xmm6 = _mm_add_epi32(xmm6, xmm5);
-			xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 8));
-			xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 4));
-
-			DATA16_RESULT(xmm6);
-
-			data_len--;
-		}
-
-		while(data_len) { /* data_len is a multiple of 2 */
-			/* 1 _mm_slli_si128 per data element less but we need shifted qlp_coeff in xmm2:xmm7 */
-			xmm6 = _mm_srli_si128(xmm3, 12);
-			xmm4 = _mm_slli_si128(xmm4, 4);
-			xmm3 = _mm_slli_si128(xmm3, 4);
-			xmm4 = _mm_or_si128(xmm4, xmm6);
-			xmm3 = _mm_insert_epi16(xmm3, curr, 1);
-
-			xmm5 = _mm_madd_epi16(xmm4, xmm7);
-			xmm6 = _mm_madd_epi16(xmm3, xmm2);
-			xmm6 = _mm_add_epi32(xmm6, xmm5);
-			xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 8));
-			xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 4));
-
-			DATA16_RESULT(xmm6);
-
-			xmm3 = _mm_insert_epi16(xmm3, curr, 0);
-
-			xmm5 = _mm_madd_epi16(xmm4, xmm1);
-			xmm6 = _mm_madd_epi16(xmm3, xmm0);
-			xmm6 = _mm_add_epi32(xmm6, xmm5);
-			xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 8));
-			xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 4));
-
-			DATA16_RESULT(xmm6);
-
-			data_len-=2;
-		}
-	} /* endif(order > 8) */
-	else
-	{
-		FLAC__int32 curr;
-		__m128i xmm0, xmm1, xmm3, xmm6;
-		xmm0 = _mm_loadu_si128((const __m128i*)(qlp_coeff+0));
-		xmm1 = _mm_loadu_si128((const __m128i*)(qlp_coeff+4));
-		xmm0 = _mm_packs_epi32(xmm0, xmm1);
-
-		xmm1 = _mm_loadu_si128((const __m128i*)(data-8));
-		xmm3 = _mm_loadu_si128((const __m128i*)(data-4));
-		xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(0,1,2,3));
-		xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(0,1,2,3));
-		xmm3 = _mm_packs_epi32(xmm3, xmm1);
-
-		/* xmm0: qlp_coeff
-			xmm3: data */
-
-		xmm6 = _mm_madd_epi16(xmm3, xmm0);
-		xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 8));
-		xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 4));
-
-		DATA16_RESULT(xmm6);
-
-		data_len--;
-
-		while(data_len) {
-			xmm3 = _mm_slli_si128(xmm3, 2);
-			xmm3 = _mm_insert_epi16(xmm3, curr, 0);
-
-			xmm6 = _mm_madd_epi16(xmm3, xmm0);
-			xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 8));
-			xmm6 = _mm_add_epi32(xmm6, _mm_srli_si128(xmm6, 4));
-
-			DATA16_RESULT(xmm6);
-
-			data_len--;
-		}
-	}
-}
-
-#endif /* defined FLAC__CPU_IA32 && !defined FLAC__HAS_NASM */
-
-#endif /* FLAC__SSE2_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
-#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/libFLAC/lpc_intrin_sse41.c b/libFLAC/lpc_intrin_sse41.c
deleted file mode 100644
index bef73f4..0000000
--- a/libFLAC/lpc_intrin_sse41.c
+++ /dev/null
@@ -1,1314 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#include "private/lpc.h"
-#ifdef FLAC__SSE4_1_SUPPORTED
-
-#include "FLAC/assert.h"
-#include "FLAC/format.h"
-
-#include <smmintrin.h> /* SSE4.1 */
-
-#if defined FLAC__CPU_IA32 /* unused for x64 */
-
-#define RESIDUAL64_RESULT(xmmN)  residual[i] = data[i] - _mm_cvtsi128_si32(_mm_srl_epi64(xmmN, cnt))
-#define RESIDUAL64_RESULT1(xmmN) residual[i] = data[i] - _mm_cvtsi128_si32(_mm_srli_epi64(xmmN, lp_quantization))
-
-FLAC__SSE_TARGET("sse4.1")
-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[])
-{
-	int i;
-	__m128i cnt = _mm_cvtsi32_si128(lp_quantization);
-
-	FLAC__ASSERT(order > 0);
-	FLAC__ASSERT(order <= 32);
-	FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm_sra_epi64() so we have to use _mm_srl_epi64() */
-
-	if(order <= 12) {
-		if(order > 8) { /* order == 9, 10, 11, 12 */
-			if(order > 10) { /* order == 11, 12 */
-				if(order == 12) {
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));  // 0  0  q[1]  q[0]
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));  // 0  0  q[3]  q[2]
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));  // 0  0  q[5]  q[4]
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));  // 0  0  q[7]  q[6]
-					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));  // 0  0  q[9]  q[8]
-					xmm5 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+10)); // 0  0  q[11] q[10]
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); // 0  q[1]  0  q[0]
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); // 0  q[3]  0  q[2]
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); // 0  q[5]  0  q[4]
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); // 0  q[7]  0  q[6]
-					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); // 0  q[9]  0  q[8]
-					xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(3,1,2,0)); // 0  q[11] 0  q[10]
-
-					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];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-12));  // 0   0        d[i-11]  d[i-12]
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); // 0  d[i-12]   0        d[i-11]
-						xmm7 = _mm_mul_epi32(xmm7, xmm5);
-
-						//sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
-						//sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-10));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm4);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
-						//sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm3);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
-						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm2);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
-						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm1);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT1(xmm7);
-					}
-				}
-				else { /* order == 11 */
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
-					xmm5 = _mm_cvtsi32_si128(qlp_coeff[10]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
-					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[10] * (FLAC__int64)data[i-11];
-						xmm7 = _mm_cvtsi32_si128(data[i-11]);
-						xmm7 = _mm_mul_epi32(xmm7, xmm5);
-
-						//sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
-						//sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-10));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm4);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
-						//sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm3);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
-						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm2);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
-						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm1);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT1(xmm7);
-					}
-				}
-			}
-			else { /* order == 9, 10 */
-				if(order == 10) {
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
-					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
-
-					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];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-10));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epi32(xmm7, xmm4);
-
-						//sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
-						//sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm3);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
-						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm2);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
-						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm1);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-				else { /* order == 9 */
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-					xmm4 = _mm_cvtsi32_si128(qlp_coeff[8]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[8] * (FLAC__int64)data[i-9];
-						xmm7 = _mm_cvtsi32_si128(data[i-9]);
-						xmm7 = _mm_mul_epi32(xmm7, xmm4);
-
-						//sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
-						//sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm3);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
-						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm2);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
-						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm1);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-			}
-		}
-		else if(order > 4) { /* order == 5, 6, 7, 8 */
-			if(order > 6) { /* order == 7, 8 */
-				if(order == 8) {
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
-
-					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];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-8));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epi32(xmm7, xmm3);
-
-						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
-						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm2);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
-						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm1);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-				else { /* order == 7 */
-					__m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-					xmm3 = _mm_cvtsi32_si128(qlp_coeff[6]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[6] * (FLAC__int64)data[i-7];
-						xmm7 = _mm_cvtsi32_si128(data[i-7]);
-						xmm7 = _mm_mul_epi32(xmm7, xmm3);
-
-						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
-						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm2);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
-						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm1);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-			}
-			else { /* order == 5, 6 */
-				if(order == 6) {
-					__m128i xmm0, xmm1, xmm2, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
-
-					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];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-6));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epi32(xmm7, xmm2);
-
-						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
-						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm1);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-				else { /* order == 5 */
-					__m128i xmm0, xmm1, xmm2, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-					xmm2 = _mm_cvtsi32_si128(qlp_coeff[4]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[4] * (FLAC__int64)data[i-5];
-						xmm7 = _mm_cvtsi32_si128(data[i-5]);
-						xmm7 = _mm_mul_epi32(xmm7, xmm2);
-
-						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
-						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm1);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-			}
-		}
-		else { /* order == 1, 2, 3, 4 */
-			if(order > 2) { /* order == 3, 4 */
-				if(order == 4) {
-					__m128i xmm0, xmm1, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
-
-					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];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-4));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epi32(xmm7, xmm1);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-				else { /* order == 3 */
-					__m128i xmm0, xmm1, xmm6, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm1 = _mm_cvtsi32_si128(qlp_coeff[2]);
-
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = 0;
-						//sum  = qlp_coeff[2] * (FLAC__int64)data[i-3];
-						xmm7 = _mm_cvtsi32_si128(data[i-3]);
-						xmm7 = _mm_mul_epi32(xmm7, xmm1);
-
-						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
-						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
-						xmm6 = _mm_mul_epi32(xmm6, xmm0);
-						xmm7 = _mm_add_epi64(xmm7, xmm6);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-			}
-			else { /* order == 1, 2 */
-				if(order == 2) {
-					__m128i xmm0, xmm7;
-					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
-
-					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];
-						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-2));
-						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
-						xmm7 = _mm_mul_epi32(xmm7, xmm0);
-
-						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-				else { /* order == 1 */
-					__m128i xmm0, xmm7;
-					xmm0 = _mm_cvtsi32_si128(qlp_coeff[0]);
-
-					for(i = 0; i < (int)data_len; i++) {
-						//sum = qlp_coeff[0] * (FLAC__int64)data[i-1];
-						xmm7 = _mm_cvtsi32_si128(data[i-1]);
-						xmm7 = _mm_mul_epi32(xmm7, xmm0);
-						RESIDUAL64_RESULT(xmm7);
-					}
-				}
-			}
-		}
-	}
-	else { /* order > 12 */
-		FLAC__int64 sum;
-		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);
-		}
-	}
-}
-
-FLAC__SSE_TARGET("sse4.1")
-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[])
-{
-	int i;
-	__m128i cnt = _mm_cvtsi32_si128(lp_quantization);
-
-	if (!data_len)
-		return;
-
-	FLAC__ASSERT(order > 0);
-	FLAC__ASSERT(order <= 32);
-	FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm_sra_epi64() so we have to use _mm_srl_epi64() */
-
-	if(order <= 12) {
-		if(order > 8) { /* order == 9, 10, 11, 12 */
-			if(order > 10) { /* order == 11, 12 */
-				__m128i qlp[6], dat[6];
-				__m128i summ, temp;
-				qlp[0] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));	// 0  0  q[1]  q[0]
-				qlp[1] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));	// 0  0  q[3]  q[2]
-				qlp[2] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));	// 0  0  q[5]  q[4]
-				qlp[3] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));	// 0  0  q[7]  q[6]
-				qlp[4] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));	// 0  0  q[9]  q[8]
-				if (order == 12)
-					qlp[5] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+10));	// 0  0  q[11] q[10]
-				else
-					qlp[5] = _mm_cvtsi32_si128(qlp_coeff[10]);					// 0  0  0     q[10]
-
-				qlp[0] = _mm_shuffle_epi32(qlp[0], _MM_SHUFFLE(2,0,3,1));	// 0  q[0]  0  q[1]
-				qlp[1] = _mm_shuffle_epi32(qlp[1], _MM_SHUFFLE(2,0,3,1));	// 0  q[2]  0  q[3]
-				qlp[2] = _mm_shuffle_epi32(qlp[2], _MM_SHUFFLE(2,0,3,1));	// 0  q[4]  0  q[5]
-				qlp[3] = _mm_shuffle_epi32(qlp[3], _MM_SHUFFLE(2,0,3,1));	// 0  q[5]  0  q[7]
-				qlp[4] = _mm_shuffle_epi32(qlp[4], _MM_SHUFFLE(2,0,3,1));	// 0  q[8]  0  q[9]
-				qlp[5] = _mm_shuffle_epi32(qlp[5], _MM_SHUFFLE(2,0,3,1));	// 0  q[10] 0  q[11]
-
-				dat[5] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-12)));	// ?  d[i-11]  ?  d[i-12]
-				dat[4] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-10)));	// ?  d[i-9]   ?  d[i-10]
-				dat[3] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-8 )));	// ?  d[i-7]   ?  d[i-8]
-				dat[2] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-6 )));	// ?  d[i-5]   ?  d[i-6]
-				dat[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-4 )));	// ?  d[i-3]   ?  d[i-4]
-				dat[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-2 )));	// ?  d[i-1]   ?  d[i-2]
-
-				summ =                     _mm_mul_epi32(dat[5], qlp[5]) ;
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[4], qlp[4]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[3], qlp[3]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));	// ?_64  sum_64
-				summ = _mm_srl_epi64(summ, cnt);						// ?_64  (sum >> lp_quantization)_64  ==  ?_32  ?_32  ?_32  (sum >> lp_quantization)_32
-				temp = _mm_cvtsi32_si128(residual[0]);					// 0  0  0  r[i]
-				temp = _mm_add_epi32(temp, summ);						// ?  ?  ?  d[i]
-				data[0] = _mm_cvtsi128_si32(temp);
-
-				for(i = 1; i < (int)data_len; i++) {
-					dat[5] = _mm_alignr_epi8(dat[4], dat[5], 8);	//  ?  d[i-10] ?  d[i-11]
-					dat[4] = _mm_alignr_epi8(dat[3], dat[4], 8);	//  ?  d[i-8]  ?  d[i-9]
-					dat[3] = _mm_alignr_epi8(dat[2], dat[3], 8);	//  ?  d[i-6]  ?  d[i-7]
-					dat[2] = _mm_alignr_epi8(dat[1], dat[2], 8);	//  ?  d[i-4]  ?  d[i-5]
-					dat[1] = _mm_alignr_epi8(dat[0], dat[1], 8);	//  ?  d[i-2]  ?  d[i-3]
-					dat[0] = _mm_alignr_epi8(temp,   dat[0], 8);	//  ?  d[i  ]  ?  d[i-1]
-
-					summ =                     _mm_mul_epi32(dat[5], qlp[5]) ;
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[4], qlp[4]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[3], qlp[3]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));	// ?_64  sum_64
-					summ = _mm_srl_epi64(summ, cnt);						// ?_64  (sum >> lp_quantization)_64  ==  ?_32  ?_32  ?_32  (sum >> lp_quantization)_32
-					temp = _mm_cvtsi32_si128(residual[i]);					// 0  0  0  r[i]
-					temp = _mm_add_epi32(temp, summ);						// ?  ?  ?  d[i]
-					data[i] = _mm_cvtsi128_si32(temp);
-				}
-			}
-			else { /* order == 9, 10 */
-				__m128i qlp[5], dat[5];
-				__m128i summ, temp;
-				qlp[0] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-				qlp[1] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-				qlp[2] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-				qlp[3] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-				if (order == 10)
-					qlp[4] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
-				else
-					qlp[4] = _mm_cvtsi32_si128(qlp_coeff[8]);
-
-				qlp[0] = _mm_shuffle_epi32(qlp[0], _MM_SHUFFLE(2,0,3,1));
-				qlp[1] = _mm_shuffle_epi32(qlp[1], _MM_SHUFFLE(2,0,3,1));
-				qlp[2] = _mm_shuffle_epi32(qlp[2], _MM_SHUFFLE(2,0,3,1));
-				qlp[3] = _mm_shuffle_epi32(qlp[3], _MM_SHUFFLE(2,0,3,1));
-				qlp[4] = _mm_shuffle_epi32(qlp[4], _MM_SHUFFLE(2,0,3,1));
-
-				dat[4] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-10)));
-				dat[3] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-8 )));
-				dat[2] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-6 )));
-				dat[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-4 )));
-				dat[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-2 )));
-
-				summ =                     _mm_mul_epi32(dat[4], qlp[4]) ;
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[3], qlp[3]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-				summ = _mm_srl_epi64(summ, cnt);
-				temp = _mm_cvtsi32_si128(residual[0]);
-				temp = _mm_add_epi32(temp, summ);
-				data[0] = _mm_cvtsi128_si32(temp);
-
-				for(i = 1; i < (int)data_len; i++) {
-					dat[4] = _mm_alignr_epi8(dat[3], dat[4], 8);
-					dat[3] = _mm_alignr_epi8(dat[2], dat[3], 8);
-					dat[2] = _mm_alignr_epi8(dat[1], dat[2], 8);
-					dat[1] = _mm_alignr_epi8(dat[0], dat[1], 8);
-					dat[0] = _mm_alignr_epi8(temp,   dat[0], 8);
-
-					summ =                     _mm_mul_epi32(dat[4], qlp[4]) ;
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[3], qlp[3]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-					summ = _mm_srl_epi64(summ, cnt);
-					temp = _mm_cvtsi32_si128(residual[i]);
-					temp = _mm_add_epi32(temp, summ);
-					data[i] = _mm_cvtsi128_si32(temp);
-				}
-			}
-		}
-		else if(order > 4) { /* order == 5, 6, 7, 8 */
-			if(order > 6) { /* order == 7, 8 */
-				__m128i qlp[4], dat[4];
-				__m128i summ, temp;
-				qlp[0] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-				qlp[1] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-				qlp[2] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-				if (order == 8)
-					qlp[3] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
-				else
-					qlp[3] = _mm_cvtsi32_si128(qlp_coeff[6]);
-
-				qlp[0] = _mm_shuffle_epi32(qlp[0], _MM_SHUFFLE(2,0,3,1));
-				qlp[1] = _mm_shuffle_epi32(qlp[1], _MM_SHUFFLE(2,0,3,1));
-				qlp[2] = _mm_shuffle_epi32(qlp[2], _MM_SHUFFLE(2,0,3,1));
-				qlp[3] = _mm_shuffle_epi32(qlp[3], _MM_SHUFFLE(2,0,3,1));
-
-				dat[3] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-8 )));
-				dat[2] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-6 )));
-				dat[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-4 )));
-				dat[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-2 )));
-
-				summ =                     _mm_mul_epi32(dat[3], qlp[3]) ;
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-				summ = _mm_srl_epi64(summ, cnt);
-				temp = _mm_cvtsi32_si128(residual[0]);
-				temp = _mm_add_epi32(temp, summ);
-				data[0] = _mm_cvtsi128_si32(temp);
-
-				for(i = 1; i < (int)data_len; i++) {
-					dat[3] = _mm_alignr_epi8(dat[2], dat[3], 8);
-					dat[2] = _mm_alignr_epi8(dat[1], dat[2], 8);
-					dat[1] = _mm_alignr_epi8(dat[0], dat[1], 8);
-					dat[0] = _mm_alignr_epi8(temp,   dat[0], 8);
-
-					summ =                     _mm_mul_epi32(dat[3], qlp[3]) ;
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-					summ = _mm_srl_epi64(summ, cnt);
-					temp = _mm_cvtsi32_si128(residual[i]);
-					temp = _mm_add_epi32(temp, summ);
-					data[i] = _mm_cvtsi128_si32(temp);
-				}
-			}
-			else { /* order == 5, 6 */
-				__m128i qlp[3], dat[3];
-				__m128i summ, temp;
-				qlp[0] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-				qlp[1] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-				if (order == 6)
-					qlp[2] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
-				else
-					qlp[2] = _mm_cvtsi32_si128(qlp_coeff[4]);
-
-				qlp[0] = _mm_shuffle_epi32(qlp[0], _MM_SHUFFLE(2,0,3,1));
-				qlp[1] = _mm_shuffle_epi32(qlp[1], _MM_SHUFFLE(2,0,3,1));
-				qlp[2] = _mm_shuffle_epi32(qlp[2], _MM_SHUFFLE(2,0,3,1));
-
-				dat[2] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-6 )));
-				dat[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-4 )));
-				dat[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-2 )));
-
-				summ =                     _mm_mul_epi32(dat[2], qlp[2]) ;
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-				summ = _mm_srl_epi64(summ, cnt);
-				temp = _mm_cvtsi32_si128(residual[0]);
-				temp = _mm_add_epi32(temp, summ);
-				data[0] = _mm_cvtsi128_si32(temp);
-
-				for(i = 1; i < (int)data_len; i++) {
-					dat[2] = _mm_alignr_epi8(dat[1], dat[2], 8);
-					dat[1] = _mm_alignr_epi8(dat[0], dat[1], 8);
-					dat[0] = _mm_alignr_epi8(temp,   dat[0], 8);
-
-					summ =                     _mm_mul_epi32(dat[2], qlp[2]) ;
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-					summ = _mm_srl_epi64(summ, cnt);
-					temp = _mm_cvtsi32_si128(residual[i]);
-					temp = _mm_add_epi32(temp, summ);
-					data[i] = _mm_cvtsi128_si32(temp);
-				}
-			}
-		}
-		else { /* order == 1, 2, 3, 4 */
-			if(order > 2) { /* order == 3, 4 */
-				__m128i qlp[2], dat[2];
-				__m128i summ, temp;
-				qlp[0] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
-				if (order == 4)
-					qlp[1] = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
-				else
-					qlp[1] = _mm_cvtsi32_si128(qlp_coeff[2]);
-
-				qlp[0] = _mm_shuffle_epi32(qlp[0], _MM_SHUFFLE(2,0,3,1));
-				qlp[1] = _mm_shuffle_epi32(qlp[1], _MM_SHUFFLE(2,0,3,1));
-
-				dat[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-4 )));
-				dat[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-2 )));
-
-				summ =                     _mm_mul_epi32(dat[1], qlp[1]) ;
-				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-				summ = _mm_srl_epi64(summ, cnt);
-				temp = _mm_cvtsi32_si128(residual[0]);
-				temp = _mm_add_epi32(temp, summ);
-				data[0] = _mm_cvtsi128_si32(temp);
-
-				for(i = 1; i < (int)data_len; i++) {
-					dat[1] = _mm_alignr_epi8(dat[0], dat[1], 8);
-					dat[0] = _mm_alignr_epi8(temp,   dat[0], 8);
-
-					summ =                     _mm_mul_epi32(dat[1], qlp[1]) ;
-					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
-
-					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-					summ = _mm_srl_epi64(summ, cnt);
-					temp = _mm_cvtsi32_si128(residual[i]);
-					temp = _mm_add_epi32(temp, summ);
-					data[i] = _mm_cvtsi128_si32(temp);
-				}
-			}
-			else { /* order == 1, 2 */
-				if(order == 2) {
-					__m128i qlp0, dat0;
-					__m128i summ, temp;
-					qlp0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff));
-					qlp0 = _mm_shuffle_epi32(qlp0, _MM_SHUFFLE(2,0,3,1));
-
-					dat0 = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(data-2 )));
-
-					summ = _mm_mul_epi32(dat0, qlp0) ;
-
-					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-					summ = _mm_srl_epi64(summ, cnt);
-					temp = _mm_cvtsi32_si128(residual[0]);
-					temp = _mm_add_epi32(temp, summ);
-					data[0] = _mm_cvtsi128_si32(temp);
-
-					for(i = 1; i < (int)data_len; i++) {
-						dat0 = _mm_alignr_epi8(temp, dat0, 8);
-
-						summ = _mm_mul_epi32(dat0, qlp0) ;
-
-						summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
-						summ = _mm_srl_epi64(summ, cnt);
-						temp = _mm_cvtsi32_si128(residual[i]);
-						temp = _mm_add_epi32(temp, summ);
-						data[i] = _mm_cvtsi128_si32(temp);
-					}
-				}
-				else { /* order == 1 */
-					__m128i qlp0;
-					__m128i summ, temp;
-					qlp0 = _mm_cvtsi32_si128(qlp_coeff[0]);
-					temp = _mm_cvtsi32_si128(data[-1]);
-
-					summ = _mm_mul_epi32(temp, qlp0);
-					summ = _mm_srl_epi64(summ, cnt);
-					temp = _mm_cvtsi32_si128(residual[0]);
-					temp = _mm_add_epi32(temp, summ);
-					data[0] = _mm_cvtsi128_si32(temp);
-
-					for(i = 1; i < (int)data_len; i++) {
-						summ = _mm_mul_epi32(temp, qlp0) ;
-						summ = _mm_srl_epi64(summ, cnt);
-						temp = _mm_cvtsi32_si128(residual[i]);
-						temp = _mm_add_epi32(temp, summ);
-						data[i] = _mm_cvtsi128_si32(temp);
-					}
-				}
-			}
-		}
-	}
-	else { /* order > 12 */
-		FLAC__int64 sum;
-		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 /* defined FLAC__CPU_IA32 */
-
-FLAC__SSE_TARGET("sse4.1")
-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[])
-{
-	int i;
-	FLAC__int32 sum;
-	__m128i cnt = _mm_cvtsi32_si128(lp_quantization);
-
-	FLAC__ASSERT(order > 0);
-	FLAC__ASSERT(order <= 32);
-
-	if(order <= 12) {
-		if(order > 8) {
-			if(order > 10) {
-				if(order == 12) {
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-					q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
-					q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
-					q10 = _mm_cvtsi32_si128(qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
-					q11 = _mm_cvtsi32_si128(qlp_coeff[11]); q11 = _mm_shuffle_epi32(q11, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q11, _mm_loadu_si128((const __m128i*)(data+i-12)));
-						mull = _mm_mullo_epi32(q10, _mm_loadu_si128((const __m128i*)(data+i-11))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 11 */
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-					q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
-					q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
-					q10 = _mm_cvtsi32_si128(qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q10, _mm_loadu_si128((const __m128i*)(data+i-11)));
-						mull = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 10) {
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-					q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
-					q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(data+i-10)));
-						mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 9 */
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-					q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(data+i-9)));
-						mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		else if(order > 4) {
-			if(order > 6) {
-				if(order == 8) {
-					__m128i q0, q1, q2, q3, q4, q5, q6, q7;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8)));
-						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 7 */
-					__m128i q0, q1, q2, q3, q4, q5, q6;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7)));
-						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 6) {
-					__m128i q0, q1, q2, q3, q4, q5;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6)));
-						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 5 */
-					__m128i q0, q1, q2, q3, q4;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5)));
-						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		else {
-			if(order > 2) {
-				if(order == 4) {
-					__m128i q0, q1, q2, q3;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4)));
-						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 3 */
-					__m128i q0, q1, q2;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3)));
-						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-			else {
-				if(order == 2) {
-					__m128i q0, q1;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ, mull;
-						summ = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2)));
-						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-				else { /* order == 1 */
-					__m128i q0;
-					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
-
-					for(i = 0; i < (int)data_len-3; i+=4) {
-						__m128i summ;
-						summ = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1)));
-						summ = _mm_sra_epi32(summ, cnt);
-						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
-					}
-				}
-			}
-		}
-		for(; i < (int)data_len; i++) {
-			sum = 0;
-			switch(order) {
-				case 12: sum += qlp_coeff[11] * data[i-12];
-				case 11: sum += qlp_coeff[10] * data[i-11];
-				case 10: sum += qlp_coeff[ 9] * data[i-10];
-				case 9:  sum += qlp_coeff[ 8] * data[i- 9];
-				case 8:  sum += qlp_coeff[ 7] * data[i- 8];
-				case 7:  sum += qlp_coeff[ 6] * data[i- 7];
-				case 6:  sum += qlp_coeff[ 5] * data[i- 6];
-				case 5:  sum += qlp_coeff[ 4] * data[i- 5];
-				case 4:  sum += qlp_coeff[ 3] * data[i- 4];
-				case 3:  sum += qlp_coeff[ 2] * data[i- 3];
-				case 2:  sum += qlp_coeff[ 1] * data[i- 2];
-				case 1:  sum += qlp_coeff[ 0] * data[i- 1];
-			}
-			residual[i] = data[i] - (sum >> 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 /* FLAC__SSE4_1_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
-#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/libFLAC/md5.c b/libFLAC/md5.c
deleted file mode 100644
index e9013a9..0000000
--- a/libFLAC/md5.c
+++ /dev/null
@@ -1,516 +0,0 @@
-#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
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- *
- * Changed so as no longer to depend on Colin Plumb's `usual.h' header
- * definitions; now uses stuff from dpkg's config.h.
- *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
- * Still in the public domain.
- *
- * Josh Coalson: made some changes to integrate with libFLAC.
- * Still in the public domain.
- */
-
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f,w,x,y,z,in,s) \
-	 (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data.  MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
-{
-	register FLAC__uint32 a, b, c, d;
-
-	a = buf[0];
-	b = buf[1];
-	c = buf[2];
-	d = buf[3];
-
-	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
-	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
-	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
-	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
-	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
-	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
-	buf[0] += a;
-	buf[1] += b;
-	buf[2] += c;
-	buf[3] += d;
-}
-
-#if WORDS_BIGENDIAN
-//@@@@@@ OPT: use bswap/intrinsics
-static void byteSwap(FLAC__uint32 *buf, unsigned words)
-{
-	register FLAC__uint32 x;
-	do {
-		x = *buf;
-		x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);
-		*buf++ = (x >> 16) | (x << 16);
-	} while (--words);
-}
-static void byteSwapX16(FLAC__uint32 *buf)
-{
-	register FLAC__uint32 x;
-
-	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.
- */
-static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, unsigned len)
-{
-	FLAC__uint32 t;
-
-	/* Update byte count */
-
-	t = ctx->bytes[0];
-	if ((ctx->bytes[0] = t + len) < t)
-		ctx->bytes[1]++;	/* Carry from low to high */
-
-	t = 64 - (t & 0x3f);	/* Space available in ctx->in (at least 1) */
-	if (t > len) {
-		memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len);
-		return;
-	}
-	/* First chunk is an odd size */
-	memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t);
-	byteSwapX16(ctx->in);
-	FLAC__MD5Transform(ctx->buf, ctx->in);
-	buf += t;
-	len -= t;
-
-	/* Process data in 64-byte chunks */
-	while (len >= 64) {
-		memcpy(ctx->in, buf, 64);
-		byteSwapX16(ctx->in);
-		FLAC__MD5Transform(ctx->buf, ctx->in);
-		buf += 64;
-		len -= 64;
-	}
-
-	/* Handle any remaining bytes of data. */
-	memcpy(ctx->in, buf, len);
-}
-
-/*
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-void FLAC__MD5Init(FLAC__MD5Context *ctx)
-{
-	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.p8 = 0;
-	ctx->capacity = 0;
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx)
-{
-	int count = ctx->bytes[0] & 0x3f;	/* Number of bytes in ctx->in */
-	FLAC__byte *p = (FLAC__byte *)ctx->in + count;
-
-	/* Set the first char of padding to 0x80.  There is always room. */
-	*p++ = 0x80;
-
-	/* Bytes of padding needed to make 56 bytes (-8..55) */
-	count = 56 - 1 - count;
-
-	if (count < 0) {	/* Padding forces an extra block */
-		memset(p, 0, count + 8);
-		byteSwapX16(ctx->in);
-		FLAC__MD5Transform(ctx->buf, ctx->in);
-		p = (FLAC__byte *)ctx->in;
-		count = 56;
-	}
-	memset(p, 0, count);
-	byteSwap(ctx->in, 14);
-
-	/* Append length in bits and transform */
-	ctx->in[14] = ctx->bytes[0] << 3;
-	ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
-	FLAC__MD5Transform(ctx->buf, ctx->in);
-
-	byteSwap(ctx->buf, 4);
-	memcpy(digest, ctx->buf, 16);
-	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) {
-		if (0 == (ctx->internal_buf.p8 = safe_realloc_(ctx->internal_buf.p8, bytes_needed))) {
-			if (0 == (ctx->internal_buf.p8 = safe_malloc_(bytes_needed))) {
-				ctx->capacity = 0;
-				return false;
-			}
-		}
-		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;
-}
diff --git a/libFLAC/memory.c b/libFLAC/memory.c
deleted file mode 100644
index a8ebd10..0000000
--- a/libFLAC/memory.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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
-
-#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;
-
-	FLAC__ASSERT(0 != aligned_address);
-
-#ifdef FLAC__ALIGN_MALLOC_DATA
-	/* align on 32-byte (256-bit) boundary */
-	x = safe_malloc_add_2op_(bytes, /*+*/31L);
-	*aligned_address = (void*)(((uintptr_t)x + 31L) & -32L);
-#else
-	x = safe_malloc_(bytes);
-	*aligned_address = x;
-#endif
-	return x;
-}
-
-FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_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);
-	FLAC__ASSERT(0 != aligned_pointer);
-	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
-
-	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;
-	}
-	else {
-		if(*unaligned_pointer != 0)
-			free(*unaligned_pointer);
-		*unaligned_pointer = pu;
-		*aligned_pointer = u.pa;
-		return true;
-	}
-}
-
-FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_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);
-	FLAC__ASSERT(0 != aligned_pointer);
-	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
-
-	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;
-	}
-	else {
-		if(*unaligned_pointer != 0)
-			free(*unaligned_pointer);
-		*unaligned_pointer = pu;
-		*aligned_pointer = u.pa;
-		return true;
-	}
-}
-
-FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_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);
-	FLAC__ASSERT(0 != aligned_pointer);
-	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
-
-	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;
-	}
-	else {
-		if(*unaligned_pointer != 0)
-			free(*unaligned_pointer);
-		*unaligned_pointer = pu;
-		*aligned_pointer = u.pa;
-		return true;
-	}
-}
-
-FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, unsigned **unaligned_pointer, unsigned **aligned_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);
-	FLAC__ASSERT(0 != aligned_pointer);
-	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
-
-	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;
-	}
-	else {
-		if(*unaligned_pointer != 0)
-			free(*unaligned_pointer);
-		*unaligned_pointer = pu;
-		*aligned_pointer = u.pa;
-		return true;
-	}
-}
-
-#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 *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);
-	FLAC__ASSERT(0 != aligned_pointer);
-	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
-
-	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;
-	}
-	else {
-		if(*unaligned_pointer != 0)
-			free(*unaligned_pointer);
-		*unaligned_pointer = pu;
-		*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);
-}
diff --git a/libFLAC/metadata_iterators.c b/libFLAC/metadata_iterators.c
deleted file mode 100644
index 0a84d03..0000000
--- a/libFLAC/metadata_iterators.c
+++ /dev/null
@@ -1,3481 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include <sys/stat.h> /* for stat(), maybe chmod() */
-
-#include "private/metadata.h"
-
-#include "FLAC/assert.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"
-
-/* 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
- *
- ***************************************************************************/
-
-static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
-static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
-static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes);
-static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes);
-static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes);
-static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes);
-
-static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
-static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
-static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length);
-static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);
-static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);
-static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length);
-static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length);
-static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length);
-static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, 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);
-static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
-static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
-static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
-static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
-static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length);
-static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length);
-static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
-static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
-static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
-static FLAC__bool write_metadata_block_data_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);
-static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last);
-static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
-
-static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
-static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
-
-static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
-static unsigned seek_to_first_metadata_block_(FILE *f);
-
-static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
-static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup);
-
-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);
-
-static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
-static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
-static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
-
-static FLAC__bool get_file_stats_(const char *filename, struct 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);
-
-static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
-
-
-#ifdef FLAC__VALGRIND_TESTING
-static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
-	size_t ret = fwrite(ptr, size, nmemb, stream);
-	if(!ferror(stream))
-		fflush(stream);
-	return ret;
-}
-#else
-#define local__fwrite fwrite
-#endif
-
-/****************************************************************************
- *
- * Level 0 implementation
- *
- ***************************************************************************/
-
-static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__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__StreamMetadata *object;
-} level0_client_data;
-
-static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
-{
-	level0_client_data cd;
-	FLAC__StreamDecoder *decoder;
-
-	FLAC__ASSERT(0 != filename);
-
-	cd.got_error = false;
-	cd.object = 0;
-
-	decoder = FLAC__stream_decoder_new();
-
-	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__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 0;
-	}
-
-	(void)FLAC__stream_decoder_finish(decoder);
-	FLAC__stream_decoder_delete(decoder);
-
-	return cd.object;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
-{
-	FLAC__StreamMetadata *object;
-
-	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != streaminfo);
-
-	object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
-
-	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;
-	}
-}
-
-FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
-{
-	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != tags);
-
-	*tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	return 0 != *tags;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
-{
-	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != cuesheet);
-
-	*cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
-
-	return 0 != *cuesheet;
-}
-
-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;
-
-	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-}
-
-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;
-
-	/*
-	 * we assume we only get here when the one metadata block we were
-	 * looking for was passed to us
-	 */
-	if(!cd->got_error && 0 == cd->object) {
-		if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
-			cd->got_error = true;
-	}
-}
-
-void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
-{
-	level0_client_data *cd = (level0_client_data *)client_data;
-	(void)decoder;
-
-	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
-		cd->got_error = true;
-}
-
-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
- *
- ***************************************************************************/
-
-#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
-/* 1 for initial offset, +4 for our own personal use */
-
-struct FLAC__Metadata_SimpleIterator {
-	FILE *file;
-	char *filename, *tempfile_path_prefix;
-	struct flac_stat_s stats;
-	FLAC__bool has_stats;
-	FLAC__bool is_writable;
-	FLAC__Metadata_SimpleIteratorStatus status;
-	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;
-	FLAC__MetadataType type;
-	unsigned length;
-};
-
-FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
-	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
-};
-
-
-FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
-{
-	FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
-
-	if(0 != iterator) {
-		iterator->file = 0;
-		iterator->filename = 0;
-		iterator->tempfile_path_prefix = 0;
-		iterator->has_stats = false;
-		iterator->is_writable = false;
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-		iterator->first_offset = iterator->offset[0] = -1;
-		iterator->depth = 0;
-	}
-
-	return iterator;
-}
-
-static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-
-	if(0 != iterator->file) {
-		fclose(iterator->file);
-		iterator->file = 0;
-		if(iterator->has_stats)
-			set_file_stats_(iterator->filename, &iterator->stats);
-	}
-	if(0 != iterator->filename) {
-		free(iterator->filename);
-		iterator->filename = 0;
-	}
-	if(0 != iterator->tempfile_path_prefix) {
-		free(iterator->tempfile_path_prefix);
-		iterator->tempfile_path_prefix = 0;
-	}
-}
-
-FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-
-	simple_iterator_free_guts_(iterator);
-	free(iterator);
-}
-
-FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__Metadata_SimpleIteratorStatus status;
-
-	FLAC__ASSERT(0 != iterator);
-
-	status = iterator->status;
-	iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-	return status;
-}
-
-static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
-{
-	unsigned ret;
-
-	FLAC__ASSERT(0 != iterator);
-
-	if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) {
-		iterator->is_writable = false;
-		if(read_only || errno == EACCES) {
-			if(0 == (iterator->file = flac_fopen(iterator->filename, "rb"))) {
-				iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
-				return false;
-			}
-		}
-		else {
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
-			return false;
-		}
-	}
-	else {
-		iterator->is_writable = true;
-	}
-
-	ret = seek_to_first_metadata_block_(iterator->file);
-	switch(ret) {
-		case 0:
-			iterator->depth = 0;
-			iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file);
-			return read_metadata_block_header_(iterator);
-		case 1:
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-			return false;
-		case 2:
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-			return false;
-		case 3:
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
-			return false;
-		default:
-			FLAC__ASSERT(0);
-			return false;
-	}
-}
-
-#if 0
-@@@ If we decide to finish implementing this, put this comment back in metadata.h
-/*
- * The 'tempfile_path_prefix' allows you to specify a directory where
- * tempfiles should go.  Remember that if your metadata edits cause the
- * FLAC file to grow, the entire file will have to be rewritten.  If
- * 'tempfile_path_prefix' is NULL, the temp file will be written in the
- * same directory as the original FLAC file.  This makes replacing the
- * original with the tempfile fast but requires extra space in the same
- * partition for the tempfile.  If space is a problem, you can pass a
- * directory name belonging to a different partition in
- * 'tempfile_path_prefix'.  Note that you should use the forward slash
- * '/' as the directory separator.  A trailing slash is not needed; it
- * will be added automatically.
- */
-FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix);
-#endif
-
-FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
-{
-	const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'flac_rename(...)' for what it will take to finish implementing this */
-
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != filename);
-
-	simple_iterator_free_guts_(iterator);
-
-	if(!read_only && preserve_file_stats)
-		iterator->has_stats = get_file_stats_(filename, &iterator->stats);
-
-	if(0 == (iterator->filename = strdup(filename))) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-		return false;
-	}
-	if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-		return false;
-	}
-
-	return simple_iterator_prime_input_(iterator, read_only);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->file);
-
-	return iterator->is_writable;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->file);
-
-	if(iterator->is_last)
-		return false;
-
-	if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	iterator->offset[iterator->depth] = ftello(iterator->file);
-
-	return read_metadata_block_header_(iterator);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__off_t this_offset;
-
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->file);
-
-	if(iterator->offset[iterator->depth] == iterator->first_offset)
-		return false;
-
-	if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-		return false;
-	}
-	this_offset = iterator->first_offset;
-	if(!read_metadata_block_header_(iterator))
-		return false;
-
-	/* we ignore any error from 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 = ftello(iterator->file);
-		if(!read_metadata_block_header_(iterator))
-			return false;
-	}
-
-	iterator->offset[iterator->depth] = this_offset;
-
-	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);
-	FLAC__ASSERT(0 != iterator->file);
-
-	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);
-
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->file);
-
-	if(0 != block) {
-		block->is_last = iterator->is_last;
-		block->length = iterator->length;
-
-		if(!read_metadata_block_data_(iterator, block)) {
-			FLAC__metadata_object_delete(block);
-			return 0;
-		}
-
-		/* back up to the beginning of the block data to stay consistent */
-		if(0 != 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;
-		}
-	}
-	else
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-
-	return block;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
-{
-	FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];)
-	FLAC__bool ret;
-
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->file);
-	FLAC__ASSERT(0 != block);
-
-	if(!iterator->is_writable) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
-		return false;
-	}
-
-	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
-		if(iterator->type != block->type) {
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
-			return false;
-		}
-	}
-
-	block->is_last = iterator->is_last;
-
-	if(iterator->length == block->length)
-		return write_metadata_block_stationary_(iterator, block);
-	else if(iterator->length > block->length) {
-		if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
-			ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
-			FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
-			FLAC__ASSERT(!ret || 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 || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
-			return ret;
-		}
-	}
-	else /* iterator->length < block->length */ {
-		unsigned padding_leftover = 0;
-		FLAC__bool padding_is_last = false;
-		if(use_padding) {
-			/* first see if we can even use padding */
-			if(iterator->is_last) {
-				use_padding = false;
-			}
-			else {
-				const unsigned extra_padding_bytes_required = block->length - iterator->length;
-				simple_iterator_push_(iterator);
-				if(!FLAC__metadata_simple_iterator_next(iterator)) {
-					(void)simple_iterator_pop_(iterator);
-					return false;
-				}
-				if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
-					use_padding = false;
-				}
-				else {
-					if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
-						padding_leftover = 0;
-						block->is_last = iterator->is_last;
-					}
-					else if(iterator->length < extra_padding_bytes_required)
-						use_padding = false;
-					else {
-						padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
-						padding_is_last = iterator->is_last;
-						block->is_last = false;
-					}
-				}
-				if(!simple_iterator_pop_(iterator))
-					return false;
-			}
-		}
-		if(use_padding) {
-			if(padding_leftover == 0) {
-				ret = write_metadata_block_stationary_(iterator, block);
-				FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
-				FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
-				return ret;
-			}
-			else {
-				FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
-				ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
-				FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
-				FLAC__ASSERT(!ret || 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 || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
-			return ret;
-		}
-	}
-}
-
-FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
-{
-	unsigned padding_leftover = 0;
-	FLAC__bool padding_is_last = false;
-
-	FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;)
-	FLAC__bool ret;
-
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->file);
-	FLAC__ASSERT(0 != block);
-
-	if(!iterator->is_writable) {
-		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;
-		return false;
-	}
-
-	block->is_last = iterator->is_last;
-
-	if(use_padding) {
-		/* first see if we can even use padding */
-		if(iterator->is_last) {
-			use_padding = false;
-		}
-		else {
-			simple_iterator_push_(iterator);
-			if(!FLAC__metadata_simple_iterator_next(iterator)) {
-				(void)simple_iterator_pop_(iterator);
-				return false;
-			}
-			if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
-				use_padding = false;
-			}
-			else {
-				if(iterator->length == block->length) {
-					padding_leftover = 0;
-					block->is_last = iterator->is_last;
-				}
-				else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
-					use_padding = false;
-				else {
-					padding_leftover = iterator->length - block->length;
-					padding_is_last = iterator->is_last;
-					block->is_last = false;
-				}
-			}
-			if(!simple_iterator_pop_(iterator))
-				return false;
-		}
-	}
-	if(use_padding) {
-		/* move to the next block, which is suitable padding */
-		if(!FLAC__metadata_simple_iterator_next(iterator))
-			return false;
-		if(padding_leftover == 0) {
-			ret = write_metadata_block_stationary_(iterator, block);
-			FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
-			FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
-			return ret;
-		}
-		else {
-			FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
-			ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
-			FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
-			FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
-			return ret;
-		}
-	}
-	else {
-		ret = rewrite_whole_file_(iterator, block, /*append=*/true);
-		FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
-		FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
-		return ret;
-	}
-}
-
-FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
-{
-	FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];)
-	FLAC__bool ret;
-
-	if(!iterator->is_writable) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
-		return false;
-	}
-
-	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
-		return false;
-	}
-
-	if(use_padding) {
-		FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
-		if(0 == padding) {
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-			return false;
-		}
-		padding->length = iterator->length;
-		if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
-			FLAC__metadata_object_delete(padding);
-			return false;
-		}
-		FLAC__metadata_object_delete(padding);
-		if(!FLAC__metadata_simple_iterator_prev(iterator))
-			return false;
-		FLAC__ASSERT(iterator->offset[iterator->depth] + (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] + (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;
-	}
-}
-
-
-
-/****************************************************************************
- *
- * Level 2 implementation
- *
- ***************************************************************************/
-
-
-typedef struct FLAC__Metadata_Node {
-	FLAC__StreamMetadata *data;
-	struct FLAC__Metadata_Node *prev, *next;
-} FLAC__Metadata_Node;
-
-struct FLAC__Metadata_Chain {
-	char *filename; /* will be NULL if using callbacks */
-	FLAC__bool is_ogg;
-	FLAC__Metadata_Node *head;
-	FLAC__Metadata_Node *tail;
-	unsigned nodes;
-	FLAC__Metadata_ChainStatus status;
-	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.
-	 */
-	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 {
-	FLAC__Metadata_Chain *chain;
-	FLAC__Metadata_Node *current;
-};
-
-FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
-	"FLAC__METADATA_CHAIN_STATUS_OK",
-	"FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
-	"FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
-	"FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
-	"FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
-	"FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
-	"FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
-	"FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
-	"FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
-	"FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
-	"FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
-	"FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
-	"FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
-	"FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
-	"FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
-	"FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
-};
-
-
-static FLAC__Metadata_Node *node_new_(void)
-{
-	return calloc(1, sizeof(FLAC__Metadata_Node));
-}
-
-static void node_delete_(FLAC__Metadata_Node *node)
-{
-	FLAC__ASSERT(0 != node);
-	if(0 != node->data)
-		FLAC__metadata_object_delete(node->data);
-	free(node);
-}
-
-static void chain_init_(FLAC__Metadata_Chain *chain)
-{
-	FLAC__ASSERT(0 != chain);
-
-	chain->filename = 0;
-	chain->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)
-{
-	FLAC__Metadata_Node *node, *next;
-
-	FLAC__ASSERT(0 != chain);
-
-	for(node = chain->head; node; ) {
-		next = node->next;
-		node_delete_(node);
-		node = next;
-	}
-
-	if(0 != chain->filename)
-		free(chain->filename);
-
-	chain_init_(chain);
-}
-
-static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
-{
-	FLAC__ASSERT(0 != chain);
-	FLAC__ASSERT(0 != node);
-	FLAC__ASSERT(0 != node->data);
-
-	node->next = node->prev = 0;
-	node->data->is_last = true;
-	if(0 != chain->tail)
-		chain->tail->data->is_last = false;
-
-	if(0 == chain->head)
-		chain->head = node;
-	else {
-		FLAC__ASSERT(0 != chain->tail);
-		chain->tail->next = node;
-		node->prev = chain->tail;
-	}
-	chain->tail = node;
-	chain->nodes++;
-}
-
-static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
-{
-	FLAC__ASSERT(0 != chain);
-	FLAC__ASSERT(0 != node);
-
-	if(node == chain->head)
-		chain->head = node->next;
-	else
-		node->prev->next = node->next;
-
-	if(node == chain->tail)
-		chain->tail = node->prev;
-	else
-		node->next->prev = node->prev;
-
-	if(0 != chain->tail)
-		chain->tail->data->is_last = true;
-
-	chain->nodes--;
-}
-
-static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
-{
-	chain_remove_node_(chain, node);
-	node_delete_(node);
-}
-
-static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
-{
-	const FLAC__Metadata_Node *node;
-	FLAC__off_t length = 0;
-	for(node = chain->head; node; node = node->next)
-		length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
-	return length;
-}
-
-static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
-{
-	FLAC__ASSERT(0 != node);
-	FLAC__ASSERT(0 != node->data);
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->current);
-	FLAC__ASSERT(0 != iterator->chain);
-	FLAC__ASSERT(0 != iterator->chain->head);
-	FLAC__ASSERT(0 != iterator->chain->tail);
-
-	node->data->is_last = false;
-
-	node->prev = iterator->current->prev;
-	node->next = iterator->current;
-
-	if(0 == node->prev)
-		iterator->chain->head = node;
-	else
-		node->prev->next = node;
-
-	iterator->current->prev = node;
-
-	iterator->chain->nodes++;
-}
-
-static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
-{
-	FLAC__ASSERT(0 != node);
-	FLAC__ASSERT(0 != node->data);
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->current);
-	FLAC__ASSERT(0 != iterator->chain);
-	FLAC__ASSERT(0 != iterator->chain->head);
-	FLAC__ASSERT(0 != iterator->chain->tail);
-
-	iterator->current->data->is_last = false;
-
-	node->prev = iterator->current;
-	node->next = iterator->current->next;
-
-	if(0 == node->next)
-		iterator->chain->tail = node;
-	else
-		node->next->prev = node;
-
-	node->prev->next = node;
-
-	iterator->chain->tail->data->is_last = true;
-
-	iterator->chain->nodes++;
-}
-
-/* return true iff node and node->next are both padding */
-static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
-{
-	if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
-		const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
-		node->data->length += growth; /* new block size can be greater than max metadata block size, but it'll be fixed later in chain_prepare_for_write_() */
-
-		chain_delete_node_(chain, node->next);
-		return true;
-	}
-	else
-		return false;
-}
-
-/* Returns the new length of the chain, or 0 if there was an error. */
-/* WATCHOUT: This can get called multiple times before a write, so
- * it should still work when this happens.
- */
-/* WATCHOUT: Make sure to also update the logic in
- * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
- */
-static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
-{
-	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 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__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))) {
-				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
-				return 0;
-			}
-			padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length);
-			if(0 == (node = node_new_())) {
-				FLAC__metadata_object_delete(padding);
-				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
-				return 0;
-			}
-			node->data = padding;
-			chain_append_node_(chain, node);
-			current_length = chain_calculate_length_(chain);
-			FLAC__ASSERT(current_length == chain->initial_length);
-		}
-		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
-		else if(current_length > chain->initial_length) {
-			const 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((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((FLAC__off_t)chain->tail->data->length >= delta) {
-					chain->tail->data->length -= delta;
-					current_length -= delta;
-					FLAC__ASSERT(current_length == chain->initial_length);
-				}
-			}
-		}
-	}
-
-	/* check sizes of all metadata blocks; reduce padding size if necessary */
-	{
-		FLAC__Metadata_Node *node;
-		for (node = chain->head; node; node = node->next) {
-			if(node->data->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
-				if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
-					node->data->length = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
-					current_length = chain_calculate_length_(chain);
-				} else {
-					chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
-					return 0;
-				}
-			}
-		}
-	}
-
-	return current_length;
-}
-
-static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb)
-{
-	FLAC__Metadata_Node *node;
-
-	FLAC__ASSERT(0 != chain);
-
-	/* we assume we're already at the beginning of the file */
-
-	switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
-		case 0:
-			break;
-		case 1:
-			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
-			return false;
-		case 2:
-			chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
-			return false;
-		case 3:
-			chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
-			return false;
-		default:
-			FLAC__ASSERT(0);
-			return false;
-	}
-
-	{
-		FLAC__int64 pos = tell_cb(handle);
-		if(pos < 0) {
-			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
-			return false;
-		}
-		chain->first_offset = (FLAC__off_t)pos;
-	}
-
-	{
-		FLAC__bool is_last;
-		FLAC__MetadataType type;
-		unsigned length;
-
-		do {
-			node = node_new_();
-			if(0 == node) {
-				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
-				return false;
-			}
-
-			if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
-				node_delete_(node);
-				chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
-				return false;
-			}
-
-			node->data = FLAC__metadata_object_new(type);
-			if(0 == node->data) {
-				node_delete_(node);
-				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
-				return false;
-			}
-
-			node->data->is_last = is_last;
-			node->data->length = length;
-
-			chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
-			if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
-				node_delete_(node);
-				return false;
-			}
-			chain_append_node_(chain, node);
-		} while(!is_last);
-	}
-
-	{
-		FLAC__int64 pos = tell_cb(handle);
-		if(pos < 0) {
-			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
-			return false;
-		}
-		chain->last_offset = (FLAC__off_t)pos;
-	}
-
-	chain->initial_length = chain_calculate_length_(chain);
-
-	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;
-
-	FLAC__ASSERT(0 != chain);
-	FLAC__ASSERT(0 != chain->head);
-
-	if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	for(node = chain->head; node; node = node->next) {
-		if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
-			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
-			return false;
-		}
-		if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
-			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
-			return false;
-		}
-	}
-
-	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
-
-	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
-	return true;
-}
-
-static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
-{
-	FILE *file;
-	FLAC__bool ret;
-
-	FLAC__ASSERT(0 != chain->filename);
-
-	if(0 == (file = flac_fopen(chain->filename, "r+b"))) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
-		return false;
-	}
-
-	/* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
-	ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
-
-	fclose(file);
-
-	return ret;
-}
-
-static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
-{
-	FILE *f, *tempfile = NULL;
-	char *tempfilename;
-	FLAC__Metadata_SimpleIteratorStatus status;
-	const FLAC__Metadata_Node *node;
-
-	FLAC__ASSERT(0 != chain);
-	FLAC__ASSERT(0 != chain->filename);
-	FLAC__ASSERT(0 != chain->head);
-
-	/* copy the file prefix (data up to first metadata block */
-	if(0 == (f = 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);
-		goto err;
-	}
-	if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
-		chain->status = get_equivalent_status_(status);
-		goto err;
-	}
-
-	/* write the metadata */
-	for(node = chain->head; node; node = node->next) {
-		if(!write_metadata_block_header_(tempfile, &status, node->data)) {
-			chain->status = get_equivalent_status_(status);
-			goto err;
-		}
-		if(!write_metadata_block_data_(tempfile, &status, node->data)) {
-			chain->status = get_equivalent_status_(status);
-			goto err;
-		}
-	}
-	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
-
-	/* copy the file postfix (everything after the metadata) */
-	if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
-		goto err;
-	}
-	if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
-		chain->status = get_equivalent_status_(status);
-		goto err;
-	}
-
-	/* move the tempfile on top of the original */
-	(void)fclose(f);
-	if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
-		return false;
-
-	return true;
-
-err:
-	(void)fclose(f);
-	cleanup_tempfile_(&tempfile, &tempfilename);
-	return false;
-}
-
-/* assumes 'handle' is already at beginning of file */
-static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb)
-{
-	FLAC__Metadata_SimpleIteratorStatus status;
-	const FLAC__Metadata_Node *node;
-
-	FLAC__ASSERT(0 != chain);
-	FLAC__ASSERT(0 == chain->filename);
-	FLAC__ASSERT(0 != chain->head);
-
-	/* copy the file prefix (data up to first metadata block */
-	if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
-		chain->status = get_equivalent_status_(status);
-		return false;
-	}
-
-	/* write the metadata */
-	for(node = chain->head; node; node = node->next) {
-		if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
-			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
-			return false;
-		}
-		if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
-			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
-			return false;
-		}
-	}
-	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
-
-	/* copy the file postfix (everything after the metadata) */
-	if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
-		return false;
-	}
-	if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
-		chain->status = get_equivalent_status_(status);
-		return false;
-	}
-
-	return true;
-}
-
-FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
-{
-	FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain));
-
-	if(0 != chain)
-		chain_init_(chain);
-
-	return chain;
-}
-
-FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
-{
-	FLAC__ASSERT(0 != chain);
-
-	chain_clear_(chain);
-
-	free(chain);
-}
-
-FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
-{
-	FLAC__Metadata_ChainStatus status;
-
-	FLAC__ASSERT(0 != chain);
-
-	status = chain->status;
-	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
-	return status;
-}
-
-static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
-{
-	FILE *file;
-	FLAC__bool ret;
-
-	FLAC__ASSERT(0 != chain);
-	FLAC__ASSERT(0 != filename);
-
-	chain_clear_(chain);
-
-	if(0 == (chain->filename = strdup(filename))) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
-		return false;
-	}
-
-	chain->is_ogg = is_ogg;
-
-	if(0 == (file = flac_fopen(filename, "rb"))) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
-		return false;
-	}
-
-	/* 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);
-
-	return ret;
-}
-
-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);
-
-	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
-		return false;
-	}
-
-	chain->is_ogg = is_ogg;
-
-	/* rewind */
-	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	/* 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 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);
-}
-
-typedef enum {
-	LBS_NONE = 0,
-	LBS_SIZE_CHANGED,
-	LBS_BLOCK_ADDED,
-	LBS_BLOCK_REMOVED
-} LastBlockState;
-
-FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
-{
-	/* This does all the same checks that are in chain_prepare_for_write_()
-	 * but doesn't actually alter the chain.  Make sure to update the logic
-	 * here if chain_prepare_for_write_() changes.
-	 */
-	FLAC__off_t current_length;
-	LastBlockState lbs_state = LBS_NONE;
-	unsigned lbs_size = 0;
-
-	FLAC__ASSERT(0 != chain);
-
-	current_length = chain_calculate_length_(chain);
-
-	if(use_padding) {
-		const FLAC__Metadata_Node * const node = chain->tail;
-		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
-		if(current_length < chain->initial_length && node->data->type == FLAC__METADATA_TYPE_PADDING) {
-			lbs_state = LBS_SIZE_CHANGED;
-			lbs_size = node->data->length + (chain->initial_length - current_length);
-		}
-		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
-		else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
-			lbs_state = LBS_BLOCK_ADDED;
-			lbs_size = chain->initial_length - (current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
-		}
-		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
-		else if(current_length > chain->initial_length) {
-			const FLAC__off_t delta = current_length - chain->initial_length;
-			if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
-				/* if the delta is exactly the size of the last padding block, remove the padding block */
-				if((FLAC__off_t)node->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
-					lbs_state = LBS_BLOCK_REMOVED;
-					lbs_size = 0;
-				}
-				/* if there is at least 'delta' bytes of padding, trim the padding down */
-				else if((FLAC__off_t)node->data->length >= delta) {
-					lbs_state = LBS_SIZE_CHANGED;
-					lbs_size = node->data->length - delta;
-				}
-			}
-		}
-	}
-
-	current_length = 0;
-	/* check sizes of all metadata blocks; reduce padding size if necessary */
-	{
-		const FLAC__Metadata_Node *node;
-		for(node = chain->head; node; node = node->next) {
-			unsigned block_len = node->data->length;
-			if(node == chain->tail) {
-				if(lbs_state == LBS_BLOCK_REMOVED)
-					continue;
-				else if(lbs_state == LBS_SIZE_CHANGED)
-					block_len = lbs_size;
-			}
-			if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
-				if(node->data->type == FLAC__METADATA_TYPE_PADDING)
-					block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
-				else
-					return false /* the return value doesn't matter */;
-			}
-			current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
-		}
-
-		if(lbs_state == LBS_BLOCK_ADDED) {
-			/* test added padding block */
-			unsigned block_len = lbs_size;
-			if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
-				block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
-			current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
-		}
-	}
-
-	return (current_length != chain->initial_length);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
-{
-	struct flac_stat_s stats;
-	const char *tempfile_path_prefix = 0;
-	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;
-	}
-
-	current_length = chain_prepare_for_write_(chain, use_padding);
-
-	/* a return value of 0 means there was an error; chain->status is already set */
-	if (0 == current_length)
-		return false;
-
-	if(preserve_file_stats)
-		get_file_stats_(chain->filename, &stats);
-
-	if(current_length == chain->initial_length) {
-		if(!chain_rewrite_metadata_in_place_(chain))
-			return false;
-	}
-	else {
-		if(!chain_rewrite_file_(chain, tempfile_path_prefix))
-			return false;
-
-		/* recompute lengths and offsets */
-		{
-			const FLAC__Metadata_Node *node;
-			chain->initial_length = current_length;
-			chain->last_offset = chain->first_offset;
-			for(node = chain->head; node; node = node->next)
-				chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
-		}
-	}
-
-	if(preserve_file_stats)
-		set_file_stats_(chain->filename, &stats);
-
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
-{
-	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;
-	}
-
-	if (0 == callbacks.write || 0 == callbacks.seek) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
-		return false;
-	}
-
-	if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
-		return false;
-	}
-
-	current_length = chain_prepare_for_write_(chain, use_padding);
-
-	/* a return value of 0 means there was an error; chain->status is already set */
-	if (0 == current_length)
-		return false;
-
-	FLAC__ASSERT(current_length == chain->initial_length);
-
-	return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks)
-{
-	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;
-	}
-
-	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
-		return false;
-	}
-	if (0 == temp_callbacks.write) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
-		return false;
-	}
-
-	if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
-		return false;
-	}
-
-	current_length = chain_prepare_for_write_(chain, use_padding);
-
-	/* a return value of 0 means there was an error; chain->status is already set */
-	if (0 == current_length)
-		return false;
-
-	FLAC__ASSERT(current_length != chain->initial_length);
-
-	/* rewind */
-	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
-		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
-		return false;
-
-	/* recompute lengths and offsets */
-	{
-		const FLAC__Metadata_Node *node;
-		chain->initial_length = current_length;
-		chain->last_offset = chain->first_offset;
-		for(node = chain->head; node; node = node->next)
-			chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
-	}
-
-	return true;
-}
-
-FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
-{
-	FLAC__Metadata_Node *node;
-
-	FLAC__ASSERT(0 != chain);
-
-	for(node = chain->head; node; ) {
-		if(!chain_merge_adjacent_padding_(chain, node))
-			node = node->next;
-	}
-}
-
-FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
-{
-	FLAC__Metadata_Node *node, *save;
-	unsigned i;
-
-	FLAC__ASSERT(0 != chain);
-
-	/*
-	 * Don't try and be too smart... this simple algo is good enough for
-	 * the small number of nodes that we deal with.
-	 */
-	for(i = 0, node = chain->head; i < chain->nodes; i++) {
-		if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
-			save = node->next;
-			chain_remove_node_(chain, node);
-			chain_append_node_(chain, node);
-			node = save;
-		}
-		else {
-			node = node->next;
-		}
-	}
-
-	FLAC__metadata_chain_merge_padding(chain);
-}
-
-
-FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
-{
-	FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iterator));
-
-	/* calloc() implies:
-		iterator->current = 0;
-		iterator->chain = 0;
-	*/
-
-	return iterator;
-}
-
-FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-
-	free(iterator);
-}
-
-FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
-{
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != chain);
-	FLAC__ASSERT(0 != chain->head);
-
-	iterator->chain = chain;
-	iterator->current = chain->head;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-
-	if(0 == iterator->current || 0 == iterator->current->next)
-		return false;
-
-	iterator->current = iterator->current->next;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-
-	if(0 == iterator->current || 0 == iterator->current->prev)
-		return false;
-
-	iterator->current = iterator->current->prev;
-	return true;
-}
-
-FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->current);
-	FLAC__ASSERT(0 != iterator->current->data);
-
-	return iterator->current->data->type;
-}
-
-FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->current);
-
-	return iterator->current->data;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
-{
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != block);
-	return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
-{
-	FLAC__Metadata_Node *save;
-
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->current);
-
-	if(0 == iterator->current->prev) {
-		FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
-		return false;
-	}
-
-	save = iterator->current->prev;
-
-	if(replace_with_padding) {
-		FLAC__metadata_object_delete_data(iterator->current->data);
-		iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
-	}
-	else {
-		chain_delete_node_(iterator->chain, iterator->current);
-	}
-
-	iterator->current = save;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
-{
-	FLAC__Metadata_Node *node;
-
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->current);
-	FLAC__ASSERT(0 != block);
-
-	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
-		return false;
-
-	if(0 == iterator->current->prev) {
-		FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
-		return false;
-	}
-
-	if(0 == (node = node_new_()))
-		return false;
-
-	node->data = block;
-	iterator_insert_node_(iterator, node);
-	iterator->current = node;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
-{
-	FLAC__Metadata_Node *node;
-
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->current);
-	FLAC__ASSERT(0 != block);
-
-	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
-		return false;
-
-	if(0 == (node = node_new_()))
-		return false;
-
-	node->data = block;
-	iterator_insert_node_after_(iterator, node);
-	iterator->current = node;
-	return true;
-}
-
-
-/****************************************************************************
- *
- * Local function definitions
- *
- ***************************************************************************/
-
-void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
-{
-	unsigned i;
-
-	b += bytes;
-
-	for(i = 0; i < bytes; i++) {
-		*(--b) = (FLAC__byte)(val & 0xff);
-		val >>= 8;
-	}
-}
-
-void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
-{
-	unsigned i;
-
-	for(i = 0; i < bytes; i++) {
-		*(b++) = (FLAC__byte)(val & 0xff);
-		val >>= 8;
-	}
-}
-
-void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes)
-{
-	unsigned i;
-
-	b += bytes;
-
-	for(i = 0; i < bytes; i++) {
-		*(--b) = (FLAC__byte)(val & 0xff);
-		val >>= 8;
-	}
-}
-
-FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes)
-{
-	FLAC__uint32 ret = 0;
-	unsigned i;
-
-	for(i = 0; i < bytes; i++)
-		ret = (ret << 8) | (FLAC__uint32)(*b++);
-
-	return ret;
-}
-
-FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes)
-{
-	FLAC__uint32 ret = 0;
-	unsigned i;
-
-	b += bytes;
-
-	for(i = 0; i < bytes; i++)
-		ret = (ret << 8) | (FLAC__uint32)(*--b);
-
-	return ret;
-}
-
-FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes)
-{
-	FLAC__uint64 ret = 0;
-	unsigned i;
-
-	for(i = 0; i < bytes; i++)
-		ret = (ret << 8) | (FLAC__uint64)(*b++);
-
-	return ret;
-}
-
-FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->file);
-
-	if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-		return false;
-	}
-
-	return true;
-}
-
-FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
-{
-	FLAC__ASSERT(0 != iterator);
-	FLAC__ASSERT(0 != iterator->file);
-
-	iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
-
-	return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
-}
-
-FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length)
-{
-	FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
-
-	if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
-		return false;
-
-	*is_last = raw_header[0] & 0x80? true : false;
-	*type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
-	*length = unpack_uint32_(raw_header + 1, 3);
-
-	/* Note that we don't check:
-	 *    if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
-	 * we just will read in an opaque block
-	 */
-
-	return true;
-}
-
-FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block)
-{
-	switch(block->type) {
-		case FLAC__METADATA_TYPE_STREAMINFO:
-			return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info);
-		case FLAC__METADATA_TYPE_PADDING:
-			return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length);
-		case FLAC__METADATA_TYPE_APPLICATION:
-			return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
-		case FLAC__METADATA_TYPE_SEEKTABLE:
-			return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length);
-		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-			return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, 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);
-	}
-}
-
-FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block)
-{
-	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
-
-	if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-
-	b = buffer;
-
-	/* we are using hardcoded numbers for simplicity but we should
-	 * probably eventually write a bit-level unpacker and use the
-	 * _STREAMINFO_ constants.
-	 */
-	block->min_blocksize = unpack_uint32_(b, 2); b += 2;
-	block->max_blocksize = unpack_uint32_(b, 2); b += 2;
-	block->min_framesize = unpack_uint32_(b, 3); b += 3;
-	block->max_framesize = unpack_uint32_(b, 3); b += 3;
-	block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((unsigned)(b[2] & 0xf0) >> 4);
-	block->channels = (unsigned)((b[2] & 0x0e) >> 1) + 1;
-	block->bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 4) | (((unsigned)(b[3] & 0xf0)) >> 4)) + 1;
-	block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
-	memcpy(block->md5sum, b+8, 16);
-
-	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-}
-
-FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length)
-{
-	(void)block; /* nothing to do; we don't care about reading the padding bytes */
-
-	if(0 != seek_cb(handle, block_length, SEEK_CUR))
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-
-	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-}
-
-FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length)
-{
-	const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
-
-	if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-
-	if(block_length < id_bytes)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-
-	block_length -= id_bytes;
-
-	if(block_length == 0) {
-		block->data = 0;
-	}
-	else {
-		if(0 == (block->data = malloc(block_length)))
-			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-
-		if(read_cb(block->data, 1, block_length, handle) != block_length)
-			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	}
-
-	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-}
-
-FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length)
-{
-	unsigned i;
-	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
-
-	FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0);
-
-	block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
-
-	if(block->num_points == 0)
-		block->points = 0;
-	else if(0 == (block->points = 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++) {
-		if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
-			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-		/* some MAGIC NUMBERs here */
-		block->points[i].sample_number = unpack_uint64_(buffer, 8);
-		block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
-		block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
-	}
-
-	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-}
-
-FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, 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 == 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);
-
-	if(entry->length == 0) {
-		entry->entry = 0;
-	}
-	else {
-		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__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, unsigned block_length)
-{
-	unsigned i;
-	FLAC__Metadata_SimpleIteratorStatus status;
-	const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
-	FLAC__byte buffer[4]; /* magic number is asserted below */
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer));
-
-	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);
-
-	if(block->num_comments == 0) {
-		block->comments = 0;
-	}
-	else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
-		block->num_comments = 0;
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-	}
-
-	for(i = 0; i < block->num_comments; i++) {
-		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;
-}
-
-FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
-{
-	unsigned i, len;
-	FLAC__byte buffer[32]; /* asserted below that this is big enough */
-
-	FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
-	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
-	FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8);
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
-	if(read_cb(buffer, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	track->offset = unpack_uint64_(buffer, len);
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
-	if(read_cb(buffer, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	track->number = (FLAC__byte)unpack_uint32_(buffer, len);
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
-	if(read_cb(track->isrc, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-
-	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
-	len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
-	if(read_cb(buffer, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1);
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1);
-	track->type = buffer[0] >> 7;
-	track->pre_emphasis = (buffer[0] >> 6) & 1;
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
-	if(read_cb(buffer, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
-
-	if(track->num_indices == 0) {
-		track->indices = 0;
-	}
-	else if(0 == (track->indices = calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-
-	for(i = 0; i < track->num_indices; i++) {
-		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
-		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
-		if(read_cb(buffer, 1, len, handle) != len)
-			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-		track->indices[i].offset = unpack_uint64_(buffer, len);
-
-		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
-		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
-		if(read_cb(buffer, 1, len, handle) != len)
-			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-		track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
-
-		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
-		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
-		if(read_cb(buffer, 1, len, handle) != len)
-			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	}
-
-	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-}
-
-FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block)
-{
-	unsigned i, len;
-	FLAC__Metadata_SimpleIteratorStatus status;
-	FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
-
-	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer));
-	FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer));
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
-	if(read_cb(block->media_catalog_number, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
-	if(read_cb(buffer, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	block->lead_in = unpack_uint64_(buffer, len);
-
-	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
-	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
-	if(read_cb(buffer, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	block->is_cd = buffer[0]&0x80? true : false;
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
-	if(read_cb(buffer, 1, len, handle) != len)
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	block->num_tracks = unpack_uint32_(buffer, len);
-
-	if(block->num_tracks == 0) {
-		block->tracks = 0;
-	}
-	else if(0 == (block->tracks = calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-
-	for(i = 0; i < block->num_tracks; i++) {
-		if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
-			return status;
-	}
-
-	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-}
-
-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) {
-		block->data = 0;
-	}
-	else {
-		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)
-			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-	}
-
-	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-}
-
-FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
-{
-	FLAC__ASSERT(0 != file);
-	FLAC__ASSERT(0 != status);
-
-	if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
-		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
-		return false;
-	}
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
-{
-	FLAC__ASSERT(0 != file);
-	FLAC__ASSERT(0 != status);
-
-	if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
-		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
-		return true;
-	}
-	else {
-		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
-		return false;
-	}
-}
-
-FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
-{
-	FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
-
-	FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
-	/* double protection */
-	if(block->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
-		return false;
-
-	buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
-	pack_uint32_(block->length, buffer + 1, 3);
-
-	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
-		return false;
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
-{
-	FLAC__ASSERT(0 != block);
-
-	switch(block->type) {
-		case FLAC__METADATA_TYPE_STREAMINFO:
-			return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
-		case FLAC__METADATA_TYPE_PADDING:
-			return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
-		case FLAC__METADATA_TYPE_APPLICATION:
-			return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
-		case FLAC__METADATA_TYPE_SEEKTABLE:
-			return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
-		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-			return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
-		case FLAC__METADATA_TYPE_CUESHEET:
-			return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
-		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);
-	}
-}
-
-FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
-{
-	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
-	const unsigned channels1 = block->channels - 1;
-	const unsigned bps1 = block->bits_per_sample - 1;
-
-	/* we are using hardcoded numbers for simplicity but we should
-	 * probably eventually write a bit-level packer and use the
-	 * _STREAMINFO_ constants.
-	 */
-	pack_uint32_(block->min_blocksize, buffer, 2);
-	pack_uint32_(block->max_blocksize, buffer+2, 2);
-	pack_uint32_(block->min_framesize, buffer+4, 3);
-	pack_uint32_(block->max_framesize, buffer+7, 3);
-	buffer[10] = (block->sample_rate >> 12) & 0xff;
-	buffer[11] = (block->sample_rate >> 4) & 0xff;
-	buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4);
-	buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
-	pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
-	memcpy(buffer+18, block->md5sum, 16);
-
-	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
-		return false;
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length)
-{
-	unsigned i, n = block_length;
-	FLAC__byte buffer[1024];
-
-	(void)block;
-
-	memset(buffer, 0, 1024);
-
-	for(i = 0; i < n/1024; i++)
-		if(write_cb(buffer, 1, 1024, handle) != 1024)
-			return false;
-
-	n %= 1024;
-
-	if(write_cb(buffer, 1, n, handle) != n)
-		return false;
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length)
-{
-	const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
-
-	if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
-		return false;
-
-	block_length -= id_bytes;
-
-	if(write_cb(block->data, 1, block_length, handle) != block_length)
-		return false;
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
-{
-	unsigned i;
-	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
-
-	for(i = 0; i < block->num_points; i++) {
-		/* some MAGIC NUMBERs here */
-		pack_uint64_(block->points[i].sample_number, buffer, 8);
-		pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
-		pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
-		if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
-			return false;
-	}
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
-{
-	unsigned i;
-	const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
-	const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
-	FLAC__byte buffer[4]; /* magic number is asserted below */
-
-	FLAC__ASSERT(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)
-		return false;
-	if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
-		return false;
-
-	pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
-	if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
-		return false;
-
-	for(i = 0; i < block->num_comments; i++) {
-		pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
-		if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
-			return false;
-		if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
-			return false;
-	}
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
-{
-	unsigned i, j, len;
-	FLAC__byte buffer[1024]; /* asserted below that this is big enough */
-
-	FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
-	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8);
-	FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8);
-	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
-	if(write_cb(block->media_catalog_number, 1, len, handle) != len)
-		return false;
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
-	pack_uint64_(block->lead_in, buffer, len);
-	if(write_cb(buffer, 1, len, handle) != len)
-		return false;
-
-	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
-	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
-	memset(buffer, 0, len);
-	if(block->is_cd)
-		buffer[0] |= 0x80;
-	if(write_cb(buffer, 1, len, handle) != len)
-		return false;
-
-	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
-	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
-	pack_uint32_(block->num_tracks, buffer, len);
-	if(write_cb(buffer, 1, len, handle) != len)
-		return false;
-
-	for(i = 0; i < block->num_tracks; i++) {
-		FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
-
-		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
-		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
-		pack_uint64_(track->offset, buffer, len);
-		if(write_cb(buffer, 1, len, handle) != len)
-			return false;
-
-		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
-		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
-		pack_uint32_(track->number, buffer, len);
-		if(write_cb(buffer, 1, len, handle) != len)
-			return false;
-
-		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
-		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
-		if(write_cb(track->isrc, 1, len, handle) != len)
-			return false;
-
-		FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
-		len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
-		memset(buffer, 0, len);
-		buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
-		if(write_cb(buffer, 1, len, handle) != len)
-			return false;
-
-		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
-		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
-		pack_uint32_(track->num_indices, buffer, len);
-		if(write_cb(buffer, 1, len, handle) != len)
-			return false;
-
-		for(j = 0; j < track->num_indices; j++) {
-			FLAC__StreamMetadata_CueSheet_Index *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_(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_(indx->number, buffer, len);
-			if(write_cb(buffer, 1, len, handle) != len)
-				return false;
-
-			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
-			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
-			memset(buffer, 0, len);
-			if(write_cb(buffer, 1, len, handle) != len)
-				return false;
-		}
-	}
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_data_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)
-		return false;
-
-	return true;
-}
-
-FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
-{
-	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
-		return false;
-
-	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
-		return false;
-
-	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	return read_metadata_block_header_(iterator);
-}
-
-FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last)
-{
-	FLAC__StreamMetadata *padding;
-
-	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	block->is_last = false;
-
-	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
-		return false;
-
-	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
-		return false;
-
-	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
-		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
-
-	padding->is_last = padding_is_last;
-	padding->length = padding_length;
-
-	if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
-		FLAC__metadata_object_delete(padding);
-		return false;
-	}
-
-	if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
-		FLAC__metadata_object_delete(padding);
-		return false;
-	}
-
-	FLAC__metadata_object_delete(padding);
-
-	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	return read_metadata_block_header_(iterator);
-}
-
-FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
-{
-	FILE *tempfile = NULL;
-	char *tempfilename = NULL;
-	int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
-	FLAC__off_t fixup_is_last_flag_offset = -1;
-
-	FLAC__ASSERT(0 != block || append == false);
-
-	if(iterator->is_last) {
-		if(append) {
-			fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
-			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
-		}
-		else if(0 == block) {
-			simple_iterator_push_(iterator);
-			if(!FLAC__metadata_simple_iterator_prev(iterator)) {
-				(void)simple_iterator_pop_(iterator);
-				return false;
-			}
-			fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
-			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
-			if(!simple_iterator_pop_(iterator))
-				return false;
-		}
-	}
-
-	if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
-		return false;
-
-	if(0 != block) {
-		if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
-			cleanup_tempfile_(&tempfile, &tempfilename);
-			return false;
-		}
-
-		if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
-			cleanup_tempfile_(&tempfile, &tempfilename);
-			return false;
-		}
-	}
-
-	if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
-		return false;
-
-	if(append)
-		return FLAC__metadata_simple_iterator_next(iterator);
-
-	return true;
-}
-
-void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
-	iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
-	iterator->depth++;
-}
-
-FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
-{
-	FLAC__ASSERT(iterator->depth > 0);
-	iterator->depth--;
-	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-		return false;
-	}
-
-	return read_metadata_block_header_(iterator);
-}
-
-/* return meanings:
- * 0: ok
- * 1: read error
- * 2: seek error
- * 3: not a FLAC file
- */
-unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb)
-{
-	FLAC__byte buffer[4];
-	size_t n;
-	unsigned i;
-
-	FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer));
-
-	/* skip any id3v2 tag */
-	errno = 0;
-	n = read_cb(buffer, 1, 4, handle);
-	if(errno)
-		return 1;
-	else if(n != 4)
-		return 3;
-	else if(0 == memcmp(buffer, "ID3", 3)) {
-		unsigned tag_length = 0;
-
-		/* skip to the tag length */
-		if(seek_cb(handle, 2, SEEK_CUR) < 0)
-			return 2;
-
-		/* read the length */
-		for(i = 0; i < 4; i++) {
-			if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80)
-				return 1;
-			tag_length <<= 7;
-			tag_length |= (buffer[0] & 0x7f);
-		}
-
-		/* skip the rest of the tag */
-		if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
-			return 2;
-
-		/* read the stream sync code */
-		errno = 0;
-		n = read_cb(buffer, 1, 4, handle);
-		if(errno)
-			return 1;
-		else if(n != 4)
-			return 3;
-	}
-
-	/* check for the fLaC signature */
-	if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
-		return 0;
-	else
-		return 3;
-}
-
-unsigned seek_to_first_metadata_block_(FILE *f)
-{
-	return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_);
-}
-
-FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
-{
-	const 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 != fseeko(iterator->file, 0, SEEK_SET)) {
-		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-		return false;
-	}
-	if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
-		cleanup_tempfile_(tempfile, tempfilename);
-		return false;
-	}
-	if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
-		cleanup_tempfile_(tempfile, tempfilename);
-		return false;
-	}
-
-	return true;
-}
-
-FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup)
-{
-	FLAC__off_t save_offset = iterator->offset[iterator->depth];
-	FLAC__ASSERT(0 != *tempfile);
-
-	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;
-	}
-	if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
-		cleanup_tempfile_(tempfile, tempfilename);
-		return false;
-	}
-
-	if(fixup_is_last_code != 0) {
-		/*
-		 * if code == 1, it means a block was appended to the end so
-		 *   we have to clear the is_last flag of the previous block
-		 * if code == -1, it means the last block was deleted so
-		 *   we have to set the is_last flag of the previous block
-		 */
-		/* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
-		FLAC__byte x;
-		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
-			cleanup_tempfile_(tempfile, tempfilename);
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-			return false;
-		}
-		if(fread(&x, 1, 1, *tempfile) != 1) {
-			cleanup_tempfile_(tempfile, tempfilename);
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-			return false;
-		}
-		if(fixup_is_last_code > 0) {
-			FLAC__ASSERT(x & 0x80);
-			x &= 0x7f;
-		}
-		else {
-			FLAC__ASSERT(!(x & 0x80));
-			x |= 0x80;
-		}
-		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
-			cleanup_tempfile_(tempfile, tempfilename);
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
-			return false;
-		}
-		if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
-			cleanup_tempfile_(tempfile, tempfilename);
-			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
-			return false;
-		}
-	}
-
-	(void)fclose(iterator->file);
-
-	if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
-		return false;
-
-	if(iterator->has_stats)
-		set_file_stats_(iterator->filename, &iterator->stats);
-
-	if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
-		return false;
-	if(backup) {
-		while(iterator->offset[iterator->depth] + (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;
-	}
-	else {
-		/* move the iterator to it's original block faster by faking a push, then doing a pop_ */
-		FLAC__ASSERT(iterator->depth == 0);
-		iterator->offset[0] = save_offset;
-		iterator->depth++;
-		return simple_iterator_pop_(iterator);
-	}
-}
-
-FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
-{
-	FLAC__byte buffer[8192];
-	size_t n;
-
-	FLAC__ASSERT(bytes >= 0);
-	while(bytes > 0) {
-		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;
-		}
-		if(local__fwrite(buffer, 1, n, tempfile) != n) {
-			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
-			return false;
-		}
-		bytes -= n;
-	}
-
-	return true;
-}
-
-FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
-{
-	FLAC__byte buffer[8192];
-	size_t n;
-
-	FLAC__ASSERT(bytes >= 0);
-	while(bytes > 0) {
-		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;
-		}
-		if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
-			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
-			return false;
-		}
-		bytes -= n;
-	}
-
-	return true;
-}
-
-FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
-{
-	FLAC__byte buffer[8192];
-	size_t n;
-
-	while(!feof(file)) {
-		n = fread(buffer, 1, sizeof(buffer), file);
-		if(n == 0 && !feof(file)) {
-			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-			return false;
-		}
-		if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
-			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
-			return false;
-		}
-	}
-
-	return true;
-}
-
-FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
-{
-	FLAC__byte buffer[8192];
-	size_t n;
-
-	while(!eof_cb(handle)) {
-		n = read_cb(buffer, 1, sizeof(buffer), handle);
-		if(n == 0 && !eof_cb(handle)) {
-			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
-			return false;
-		}
-		if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
-			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
-			return false;
-		}
-	}
-
-	return true;
-}
-
-static int
-local_snprintf(char *str, size_t size, const char *fmt, ...)
-{
-	va_list va;
-	int rc;
-
-#if defined _MSC_VER
-	if (size == 0)
-		return 1024;
-#endif
-
-	va_start (va, fmt);
-
-#if defined _MSC_VER
-	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) {
-		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;
-		}
-		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++;
-
-		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;
-		}
-		local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix);
-	}
-
-	if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) {
-		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
-		return false;
-	}
-
-	return true;
-}
-
-FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
-{
-	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != tempfile);
-	FLAC__ASSERT(0 != *tempfile);
-	FLAC__ASSERT(0 != tempfilename);
-	FLAC__ASSERT(0 != *tempfilename);
-	FLAC__ASSERT(0 != status);
-
-	(void)fclose(*tempfile);
-	*tempfile = 0;
-
-#if defined _MSC_VER || defined __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;
-	}
-#endif
-
-	/*@@@ 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;
-	}
-
-	cleanup_tempfile_(tempfile, tempfilename);
-
-	return true;
-}
-
-void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
-{
-	if(0 != *tempfile) {
-		(void)fclose(*tempfile);
-		*tempfile = 0;
-	}
-
-	if(0 != *tempfilename) {
-		(void)flac_unlink(*tempfilename);
-		free(*tempfilename);
-		*tempfilename = 0;
-	}
-}
-
-FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
-{
-	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != stats);
-	return (0 == flac_stat(filename, stats));
-}
-
-void set_file_stats_(const char *filename, struct flac_stat_s *stats)
-{
-	struct utimbuf srctime;
-
-	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != stats);
-
-	srctime.actime = stats->st_atime;
-	srctime.modtime = stats->st_mtime;
-	(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
-}
-
-int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
-{
-	return fseeko((FILE*)handle, (FLAC__off_t)offset, whence);
-}
-
-FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
-{
-	return ftello((FILE*)handle);
-}
-
-FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
-{
-	switch(status) {
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
-			return FLAC__METADATA_CHAIN_STATUS_OK;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
-			return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
-			return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
-			return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
-			return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
-			return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
-			return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
-			return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
-			return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
-			return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
-			return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
-			return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
-		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
-		default:
-			return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
-	}
-}
diff --git a/libFLAC/metadata_object.c b/libFLAC/metadata_object.c
deleted file mode 100644
index 9cb9501..0000000
--- a/libFLAC/metadata_object.c
+++ /dev/null
@@ -1,1821 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/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
- *
- ***************************************************************************/
-
-/* 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(to != NULL);
-	if (bytes > 0 && from != NULL) {
-		FLAC__byte *x;
-		if ((x = safe_malloc_(bytes)) == NULL)
-			return false;
-		memcpy(x, from, bytes);
-		*to = x;
-	}
-	else {
-		*to = 0;
-	}
-	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(to != NULL);
-	if (copy_bytes_(&copy, from, bytes)) {
-		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 (x != NULL) {
-		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 != NULL);
-	if (copy) {
-		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;
-	if (from->entry == 0) {
-		FLAC__ASSERT(from->length == 0);
-		to->entry = 0;
-	}
-	else {
-		FLAC__byte *x;
-		FLAC__ASSERT(from->length > 0);
-		if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL)
-			return false;
-		memcpy(x, from->entry, from->length);
-		x[from->length] = '\0';
-		to->entry = x;
-	}
-	return true;
-}
-
-static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
-{
-	memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
-	if (from->indices == 0) {
-		FLAC__ASSERT(from->num_indices == 0);
-	}
-	else {
-		FLAC__StreamMetadata_CueSheet_Index *x;
-		FLAC__ASSERT(from->num_indices > 0);
-		if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL)
-			return false;
-		memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
-		to->indices = x;
-	}
-	return true;
-}
-
-static void seektable_calculate_length_(FLAC__StreamMetadata *object)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-
-	object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
-}
-
-static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points)
-{
-	FLAC__StreamMetadata_SeekPoint *object_array;
-
-	FLAC__ASSERT(num_points > 0);
-
-	object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
-
-	if (object_array != NULL) {
-		unsigned i;
-		for (i = 0; i < num_points; i++) {
-			object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
-			object_array[i].stream_offset = 0;
-			object_array[i].frame_samples = 0;
-		}
-	}
-
-	return object_array;
-}
-
-static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
-{
-	unsigned i;
-
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
-	object->length += object->data.vorbis_comment.vendor_string.length;
-	object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
-	for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
-		object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
-		object->length += object->data.vorbis_comment.comments[i].length;
-	}
-}
-
-static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(unsigned num_comments)
-{
-	FLAC__ASSERT(num_comments > 0);
-
-	return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
-}
-
-static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
-{
-	unsigned i;
-
-	FLAC__ASSERT(object_array != NULL && num_comments > 0);
-
-	for (i = 0; i < num_comments; i++)
-		free(object_array[i].entry);
-
-	free(object_array);
-}
-
-static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
-{
-	FLAC__StreamMetadata_VorbisComment_Entry *return_array;
-
-	FLAC__ASSERT(object_array != NULL);
-	FLAC__ASSERT(num_comments > 0);
-
-	return_array = vorbiscomment_entry_array_new_(num_comments);
-
-	if (return_array != NULL) {
-		unsigned i;
-
-		for (i = 0; i < num_comments; i++) {
-			if (!copy_vcentry_(return_array+i, object_array+i)) {
-				vorbiscomment_entry_array_delete_(return_array, num_comments);
-				return 0;
-			}
-		}
-	}
-
-	return return_array;
-}
-
-static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
-{
-	FLAC__byte *save;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(dest != NULL);
-	FLAC__ASSERT(src != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-	FLAC__ASSERT((src->entry != NULL && src->length > 0) || (src->entry == NULL && src->length == 0));
-
-	save = dest->entry;
-
-	if (src->entry != NULL) {
-		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 {
-		/* the src is null */
-		*dest = *src;
-	}
-
-	free(save);
-
-	vorbiscomment_calculate_length_(object);
-	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(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-	FLAC__ASSERT(field_name != NULL);
-
-	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;
-
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
-
-	object->length = (
-		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
-	) / 8;
-
-	object->length += object->data.cue_sheet.num_tracks * (
-		FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
-		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
-	) / 8;
-
-	for (i = 0; i < object->data.cue_sheet.num_tracks; i++) {
-		object->length += object->data.cue_sheet.tracks[i].num_indices * (
-			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
-			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
-			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
-		) / 8;
-	}
-}
-
-static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsigned num_indices)
-{
-	FLAC__ASSERT(num_indices > 0);
-
-	return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
-}
-
-static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
-{
-	FLAC__ASSERT(num_tracks > 0);
-
-	return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
-}
-
-static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
-{
-	unsigned i;
-
-	FLAC__ASSERT(object_array != NULL && num_tracks > 0);
-
-	for (i = 0; i < num_tracks; i++) {
-		if (object_array[i].indices != 0) {
-			FLAC__ASSERT(object_array[i].num_indices > 0);
-			free(object_array[i].indices);
-		}
-	}
-
-	free(object_array);
-}
-
-static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
-{
-	FLAC__StreamMetadata_CueSheet_Track *return_array;
-
-	FLAC__ASSERT(object_array != NULL);
-	FLAC__ASSERT(num_tracks > 0);
-
-	return_array = cuesheet_track_array_new_(num_tracks);
-
-	if (return_array != NULL) {
-		unsigned i;
-
-		for (i = 0; i < num_tracks; i++) {
-			if (!copy_track_(return_array+i, object_array+i)) {
-				cuesheet_track_array_delete_(return_array, num_tracks);
-				return 0;
-			}
-		}
-	}
-
-	return return_array;
-}
-
-static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
-{
-	FLAC__StreamMetadata_CueSheet_Index *save;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(dest != NULL);
-	FLAC__ASSERT(src != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
-	FLAC__ASSERT((src->indices != NULL && src->num_indices > 0) || (src->indices == NULL && src->num_indices == 0));
-
-	save = dest->indices;
-
-	/* do the copy first so that if we fail we leave the object untouched */
-	if (copy) {
-		if (!copy_track_(dest, src))
-			return false;
-	}
-	else {
-		*dest = *src;
-	}
-
-	free(save);
-
-	cuesheet_calculate_length_(object);
-	return true;
-}
-
-
-/****************************************************************************
- *
- * Metadata object routines
- *
- ***************************************************************************/
-
-FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
-{
-	FLAC__StreamMetadata *object;
-
-	if (type > FLAC__MAX_METADATA_TYPE)
-		return 0;
-
-	object = calloc(1, sizeof(FLAC__StreamMetadata));
-	if (object != NULL) {
-		object->is_last = false;
-		object->type = type;
-		switch(type) {
-			case FLAC__METADATA_TYPE_STREAMINFO:
-				object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
-				break;
-			case FLAC__METADATA_TYPE_PADDING:
-				/* calloc() took care of this for us:
-				object->length = 0;
-				*/
-				break;
-			case FLAC__METADATA_TYPE_APPLICATION:
-				object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
-				/* calloc() took care of this for us:
-				object->data.application.data = 0;
-				*/
-				break;
-			case FLAC__METADATA_TYPE_SEEKTABLE:
-				/* calloc() took care of this for us:
-				object->length = 0;
-				object->data.seek_table.num_points = 0;
-				object->data.seek_table.points = 0;
-				*/
-				break;
-			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-				object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
-				if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+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), "")) {
-					free(object->data.picture.mime_type);
-					free(object);
-					return 0;
-				}
-				break;
-			default:
-				/* calloc() took care of this for us:
-				object->length = 0;
-				object->data.unknown.data = 0;
-				*/
-				break;
-		}
-	}
-
-	return object;
-}
-
-FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
-{
-	FLAC__StreamMetadata *to;
-
-	FLAC__ASSERT(object != NULL);
-
-	if ((to = FLAC__metadata_object_new(object->type)) != NULL) {
-		to->is_last = object->is_last;
-		to->type = object->type;
-		to->length = object->length;
-		switch(to->type) {
-			case FLAC__METADATA_TYPE_STREAMINFO:
-				memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
-				break;
-			case FLAC__METADATA_TYPE_PADDING:
-				break;
-			case FLAC__METADATA_TYPE_APPLICATION:
-				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);
-					return 0;
-				}
-				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;
-				}
-				break;
-			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-				if (to->data.vorbis_comment.vendor_string.entry != NULL) {
-					free(to->data.vorbis_comment.vendor_string.entry);
-					to->data.vorbis_comment.vendor_string.entry = 0;
-				}
-				if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
-					FLAC__metadata_object_delete(to);
-					return 0;
-				}
-				if (object->data.vorbis_comment.num_comments == 0) {
-					to->data.vorbis_comment.comments = 0;
-				}
-				else {
-					to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
-					if (to->data.vorbis_comment.comments == NULL) {
-						to->data.vorbis_comment.num_comments = 0;
-						FLAC__metadata_object_delete(to);
-						return 0;
-					}
-				}
-				to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
-				break;
-			case FLAC__METADATA_TYPE_CUESHEET:
-				memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
-				if (object->data.cue_sheet.num_tracks == 0) {
-					FLAC__ASSERT(object->data.cue_sheet.tracks == NULL);
-				}
-				else {
-					FLAC__ASSERT(object->data.cue_sheet.tracks != 0);
-					to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
-					if (to->data.cue_sheet.tracks == NULL) {
-						FLAC__metadata_object_delete(to);
-						return 0;
-					}
-				}
-				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);
-					return 0;
-				}
-				break;
-		}
-	}
-
-	return to;
-}
-
-void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
-{
-	FLAC__ASSERT(object != NULL);
-
-	switch(object->type) {
-		case FLAC__METADATA_TYPE_STREAMINFO:
-		case FLAC__METADATA_TYPE_PADDING:
-			break;
-		case FLAC__METADATA_TYPE_APPLICATION:
-			if (object->data.application.data != NULL) {
-				free(object->data.application.data);
-				object->data.application.data = NULL;
-			}
-			break;
-		case FLAC__METADATA_TYPE_SEEKTABLE:
-			if (object->data.seek_table.points != NULL) {
-				free(object->data.seek_table.points);
-				object->data.seek_table.points = NULL;
-			}
-			break;
-		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-			if (object->data.vorbis_comment.vendor_string.entry != NULL) {
-				free(object->data.vorbis_comment.vendor_string.entry);
-				object->data.vorbis_comment.vendor_string.entry = 0;
-			}
-			if (object->data.vorbis_comment.comments != NULL) {
-				FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
-				vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
-				object->data.vorbis_comment.comments = NULL;
-				object->data.vorbis_comment.num_comments = 0;
-			}
-			break;
-		case FLAC__METADATA_TYPE_CUESHEET:
-			if (object->data.cue_sheet.tracks != NULL) {
-				FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
-				cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
-				object->data.cue_sheet.tracks = NULL;
-				object->data.cue_sheet.num_tracks = 0;
-			}
-			break;
-		case FLAC__METADATA_TYPE_PICTURE:
-			if (object->data.picture.mime_type != NULL) {
-				free(object->data.picture.mime_type);
-				object->data.picture.mime_type = NULL;
-			}
-			if (object->data.picture.description != NULL) {
-				free(object->data.picture.description);
-				object->data.picture.description = NULL;
-			}
-			if (object->data.picture.data != NULL) {
-				free(object->data.picture.data);
-				object->data.picture.data = NULL;
-			}
-			break;
-		default:
-			if (object->data.unknown.data != NULL) {
-				free(object->data.unknown.data);
-				object->data.unknown.data = NULL;
-			}
-			break;
-	}
-}
-
-FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
-{
-	FLAC__metadata_object_delete_data(object);
-	free(object);
-}
-
-static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2)
-{
-	if (block1->min_blocksize != block2->min_blocksize)
-		return false;
-	if (block1->max_blocksize != block2->max_blocksize)
-		return false;
-	if (block1->min_framesize != block2->min_framesize)
-		return false;
-	if (block1->max_framesize != block2->max_framesize)
-		return false;
-	if (block1->sample_rate != block2->sample_rate)
-		return false;
-	if (block1->channels != block2->channels)
-		return false;
-	if (block1->bits_per_sample != block2->bits_per_sample)
-		return false;
-	if (block1->total_samples != block2->total_samples)
-		return false;
-	if (memcmp(block1->md5sum, block2->md5sum, 16) != 0)
-		return false;
-	return true;
-}
-
-static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, unsigned block_length)
-{
-	FLAC__ASSERT(block1 != NULL);
-	FLAC__ASSERT(block2 != NULL);
-	FLAC__ASSERT(block_length >= sizeof(block1->id));
-
-	if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0)
-		return false;
-	if (block1->data != NULL && block2->data != NULL)
-		return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0;
-	else
-		return block1->data == block2->data;
-}
-
-static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
-{
-	unsigned i;
-
-	FLAC__ASSERT(block1 != NULL);
-	FLAC__ASSERT(block2 != NULL);
-
-	if (block1->num_points != block2->num_points)
-		return false;
-
-	if (block1->points != NULL && block2->points != NULL) {
-		for (i = 0; i < block1->num_points; i++) {
-			if (block1->points[i].sample_number != block2->points[i].sample_number)
-				return false;
-			if (block1->points[i].stream_offset != block2->points[i].stream_offset)
-				return false;
-			if (block1->points[i].frame_samples != block2->points[i].frame_samples)
-				return false;
-		}
-		return true;
-	}
-	else
-		return block1->points == block2->points;
-}
-
-static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2)
-{
-	unsigned i;
-
-	if (block1->vendor_string.length != block2->vendor_string.length)
-		return false;
-
-	if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) {
-		if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0)
-			return false;
-	}
-	else if (block1->vendor_string.entry != block2->vendor_string.entry)
-		return false;
-
-	if (block1->num_comments != block2->num_comments)
-		return false;
-
-	for (i = 0; i < block1->num_comments; i++) {
-		if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) {
-			if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0)
-				return false;
-		}
-		else if (block1->comments[i].entry != block2->comments[i].entry)
-			return false;
-	}
-	return true;
-}
-
-static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
-{
-	unsigned i, j;
-
-	if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0)
-		return false;
-
-	if (block1->lead_in != block2->lead_in)
-		return false;
-
-	if (block1->is_cd != block2->is_cd)
-		return false;
-
-	if (block1->num_tracks != block2->num_tracks)
-		return false;
-
-	if (block1->tracks != NULL && block2->tracks != NULL) {
-		FLAC__ASSERT(block1->num_tracks > 0);
-		for (i = 0; i < block1->num_tracks; i++) {
-			if (block1->tracks[i].offset != block2->tracks[i].offset)
-				return false;
-			if (block1->tracks[i].number != block2->tracks[i].number)
-				return false;
-			if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0)
-				return false;
-			if (block1->tracks[i].type != block2->tracks[i].type)
-				return false;
-			if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
-				return false;
-			if (block1->tracks[i].num_indices != block2->tracks[i].num_indices)
-				return false;
-			if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) {
-				FLAC__ASSERT(block1->tracks[i].num_indices > 0);
-				for (j = 0; j < block1->tracks[i].num_indices; j++) {
-					if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
-						return false;
-					if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
-						return false;
-				}
-			}
-			else if (block1->tracks[i].indices != block2->tracks[i].indices)
-				return false;
-		}
-	}
-	else if (block1->tracks != block2->tracks)
-		return false;
-	return true;
-}
-
-static FLAC__bool compare_block_data_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 && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type)))
-		return false;
-	if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || 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 && (block1->data == NULL || block2->data == NULL || 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(block1 != NULL);
-	FLAC__ASSERT(block2 != NULL);
-
-	if (block1->data != NULL && block2->data != NULL)
-		return memcmp(block1->data, block2->data, block_length) == 0;
-	else
-		return block1->data == block2->data;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
-{
-	FLAC__ASSERT(block1 != NULL);
-	FLAC__ASSERT(block2 != NULL);
-
-	if (block1->type != block2->type) {
-		return false;
-	}
-	if (block1->is_last != block2->is_last) {
-		return false;
-	}
-	if (block1->length != block2->length) {
-		return false;
-	}
-	switch(block1->type) {
-		case FLAC__METADATA_TYPE_STREAMINFO:
-			return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
-		case FLAC__METADATA_TYPE_PADDING:
-			return true; /* we don't compare the padding guts */
-		case FLAC__METADATA_TYPE_APPLICATION:
-			return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
-		case FLAC__METADATA_TYPE_SEEKTABLE:
-			return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
-		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-			return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
-		case FLAC__METADATA_TYPE_CUESHEET:
-			return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
-		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);
-	}
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy)
-{
-	FLAC__byte *save;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
-	FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false));
-
-	save = object->data.application.data;
-
-	/* do the copy first so that if we fail we leave the object untouched */
-	if (copy) {
-		if (!copy_bytes_(&object->data.application.data, data, length))
-			return false;
-	}
-	else {
-		object->data.application.data = data;
-	}
-
-	free(save);
-
-	object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-
-	if (object->data.seek_table.points == 0) {
-		FLAC__ASSERT(object->data.seek_table.num_points == 0);
-		if (new_num_points == 0)
-			return true;
-		else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0)
-			return false;
-	}
-	else {
-		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) {
-			free(object->data.seek_table.points);
-			object->data.seek_table.points = 0;
-		}
-		else if ((object->data.seek_table.points = safe_realloc_(object->data.seek_table.points, new_size)) == NULL)
-			return false;
-
-		/* if growing, set new elements to placeholders */
-		if (new_size > old_size) {
-			unsigned i;
-			for (i = object->data.seek_table.num_points; i < new_num_points; i++) {
-				object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
-				object->data.seek_table.points[i].stream_offset = 0;
-				object->data.seek_table.points[i].frame_samples = 0;
-			}
-		}
-	}
-
-	object->data.seek_table.num_points = new_num_points;
-
-	seektable_calculate_length_(object);
-	return true;
-}
-
-FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
-
-	object->data.seek_table.points[point_num] = point;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
-{
-	int i;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-	FLAC__ASSERT(point_num <= object->data.seek_table.num_points);
-
-	if (!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
-		return false;
-
-	/* move all points >= point_num forward one space */
-	for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
-		object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
-
-	FLAC__metadata_object_seektable_set_point(object, point_num, point);
-	seektable_calculate_length_(object);
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num)
-{
-	unsigned i;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
-
-	/* move all points > point_num backward one space */
-	for (i = point_num; i < object->data.seek_table.num_points-1; i++)
-		object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
-
-	return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-
-	return FLAC__format_seektable_is_legal(&object->data.seek_table);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-
-	if (num > 0)
-		/* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
-		return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
-	else
-		return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
-{
-	FLAC__StreamMetadata_SeekTable *seek_table;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-
-	seek_table = &object->data.seek_table;
-
-	if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
-		return false;
-
-	seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
-	seek_table->points[seek_table->num_points - 1].stream_offset = 0;
-	seek_table->points[seek_table->num_points - 1].frame_samples = 0;
-
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-	FLAC__ASSERT(sample_numbers != 0 || num == 0);
-
-	if (num > 0) {
-		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
-		unsigned i, j;
-
-		i = seek_table->num_points;
-
-		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
-			return false;
-
-		for (j = 0; j < num; i++, j++) {
-			seek_table->points[i].sample_number = sample_numbers[j];
-			seek_table->points[i].stream_offset = 0;
-			seek_table->points[i].frame_samples = 0;
-		}
-	}
-
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-	FLAC__ASSERT(total_samples > 0);
-
-	if (num > 0 && total_samples > 0) {
-		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
-		unsigned i, j;
-
-		i = seek_table->num_points;
-
-		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
-			return false;
-
-		for (j = 0; j < num; i++, j++) {
-			seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
-			seek_table->points[i].stream_offset = 0;
-			seek_table->points[i].frame_samples = 0;
-		}
-	}
-
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples)
-{
-	FLAC__ASSERT(object != NULL);
-	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--;
-
-		/* Put a strict upper bound on the number of allowed seek points. */
-		if (num > 32768) {
-			/* Set the bound and recalculate samples accordingly. */
-			num = 32768;
-			samples = total_samples / 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;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-
-	unique = FLAC__format_seektable_sort(&object->data.seek_table);
-
-	return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
-{
-	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);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	if (object->data.vorbis_comment.comments == NULL) {
-		FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0);
-		if (new_num_comments == 0)
-			return true;
-		else if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL)
-			return false;
-	}
-	else {
-		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 */
-		if (new_num_comments < object->data.vorbis_comment.num_comments) {
-			unsigned i;
-			for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
-				if (object->data.vorbis_comment.comments[i].entry != NULL)
-					free(object->data.vorbis_comment.comments[i].entry);
-		}
-
-		if (new_size == 0) {
-			free(object->data.vorbis_comment.comments);
-			object->data.vorbis_comment.comments = 0;
-		}
-		else {
-			FLAC__StreamMetadata_VorbisComment_Entry *oldptr = object->data.vorbis_comment.comments;
-			if ((object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) {
-				vorbiscomment_entry_array_delete_(oldptr, object->data.vorbis_comment.num_comments);
-				object->data.vorbis_comment.num_comments = 0;
-				return false;
-			}
-		}
-
-		/* if growing, zero all the length/pointers of new elements */
-		if (new_size > old_size)
-			memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
-	}
-
-	object->data.vorbis_comment.num_comments = new_num_comments;
-
-	vorbiscomment_calculate_length_(object);
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
-{
-	FLAC__ASSERT(object != NULL);
-	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);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
-{
-	FLAC__StreamMetadata_VorbisComment *vc;
-
-	FLAC__ASSERT(object != NULL);
-	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))
-		return false;
-
-	/* move all comments >= comment_num forward one space */
-	memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
-	vc->comments[comment_num].length = 0;
-	vc->comments[comment_num].entry = 0;
-
-	return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
-{
-	FLAC__ASSERT(object != NULL);
-	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(entry.entry != NULL && 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);
-
-		if (eq == NULL)
-			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;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-	FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
-
-	vc = &object->data.vorbis_comment;
-
-	/* free the comment at comment_num */
-	free(vc->comments[comment_num].entry);
-
-	/* move all comments > comment_num backward one space */
-	memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
-	vc->comments[vc->num_comments-1].length = 0;
-	vc->comments[vc->num_comments-1].entry = 0;
-
-	return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
-{
-	FLAC__ASSERT(entry != NULL);
-	FLAC__ASSERT(field_name != NULL);
-	FLAC__ASSERT(field_value != NULL);
-
-	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 ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL)
-			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 FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
-{
-	FLAC__ASSERT(entry.entry != NULL && entry.length > 0);
-	FLAC__ASSERT(field_name != NULL);
-	FLAC__ASSERT(field_value != NULL);
-
-	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
-		return false;
-
-	{
-		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 '=' */
-
-		if (eq == NULL)
-			return false; /* double protection */
-		if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL)
-			return false;
-		if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) {
-			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 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(entry.entry != NULL && entry.length > 0);
-	{
-		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
-		return (eq != NULL && (unsigned)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0);
-	}
-}
-
-FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
-{
-	FLAC__ASSERT(field_name != NULL);
-
-	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);
-	unsigned i;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
-		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
-			if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
-				return -1;
-			else
-				return 1;
-		}
-	}
-
-	return 0;
-}
-
-FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
-{
-	FLAC__bool ok = true;
-	unsigned matching = 0;
-	const unsigned field_name_length = strlen(field_name);
-	int i;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	/* must delete from end to start otherwise it will interfere with our iteration */
-	for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
-		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
-			matching++;
-			ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i);
-		}
-	}
-
-	return ok? (int)matching : -1;
-}
-
-FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
-{
-	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)
-{
-	FLAC__StreamMetadata_CueSheet_Track *to;
-
-	FLAC__ASSERT(object != NULL);
-
-	if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) {
-		if (!copy_track_(to, object)) {
-			FLAC__metadata_object_cuesheet_track_delete(to);
-			return 0;
-		}
-	}
-
-	return to;
-}
-
-void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
-{
-	FLAC__ASSERT(object != NULL);
-
-	if (object->indices != NULL) {
-		FLAC__ASSERT(object->num_indices > 0);
-		free(object->indices);
-	}
-}
-
-FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
-{
-	FLAC__metadata_object_cuesheet_track_delete_data(object);
-	free(object);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices)
-{
-	FLAC__StreamMetadata_CueSheet_Track *track;
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
-	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
-
-	track = &object->data.cue_sheet.tracks[track_num];
-
-	if (track->indices == NULL) {
-		FLAC__ASSERT(track->num_indices == 0);
-		if (new_num_indices == 0)
-			return true;
-		else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL)
-			return false;
-	}
-	else {
-		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) {
-			free(track->indices);
-			track->indices = 0;
-		}
-		else if ((track->indices = safe_realloc_(track->indices, new_size)) == NULL)
-			return false;
-
-		/* if growing, zero all the lengths/pointers of new elements */
-		if (new_size > old_size)
-			memset(track->indices + track->num_indices, 0, new_size - old_size);
-	}
-
-	track->num_indices = new_num_indices;
-
-	cuesheet_calculate_length_(object);
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index indx)
-{
-	FLAC__StreamMetadata_CueSheet_Track *track;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
-	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
-	FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices);
-
-	track = &object->data.cue_sheet.tracks[track_num];
-
-	if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
-		return false;
-
-	/* move all indices >= index_num forward one space */
-	memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
-
-	track->indices[index_num] = indx;
-	cuesheet_calculate_length_(object);
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
-{
-	FLAC__StreamMetadata_CueSheet_Index 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)
-{
-	FLAC__StreamMetadata_CueSheet_Track *track;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
-	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
-	FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices);
-
-	track = &object->data.cue_sheet.tracks[track_num];
-
-	/* move all indices > index_num backward one space */
-	memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
-
-	FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
-	cuesheet_calculate_length_(object);
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
-
-	if (object->data.cue_sheet.tracks == NULL) {
-		FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
-		if (new_num_tracks == 0)
-			return true;
-		else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL)
-			return false;
-	}
-	else {
-		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 */
-		if (new_num_tracks < object->data.cue_sheet.num_tracks) {
-			unsigned i;
-			for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
-				free(object->data.cue_sheet.tracks[i].indices);
-		}
-
-		if (new_size == 0) {
-			free(object->data.cue_sheet.tracks);
-			object->data.cue_sheet.tracks = 0;
-		}
-		else if ((object->data.cue_sheet.tracks = safe_realloc_(object->data.cue_sheet.tracks, new_size)) == NULL)
-			return false;
-
-		/* if growing, zero all the lengths/pointers of new elements */
-		if (new_size > old_size)
-			memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
-	}
-
-	object->data.cue_sheet.num_tracks = new_num_tracks;
-
-	cuesheet_calculate_length_(object);
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
-{
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
-
-	return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
-{
-	FLAC__StreamMetadata_CueSheet *cs;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
-	FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks);
-
-	cs = &object->data.cue_sheet;
-
-	if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
-		return false;
-
-	/* move all tracks >= track_num forward one space */
-	memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
-	cs->tracks[track_num].num_indices = 0;
-	cs->tracks[track_num].indices = 0;
-
-	return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num)
-{
-	FLAC__StreamMetadata_CueSheet_Track track;
-	memset(&track, 0, sizeof(track));
-	return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num)
-{
-	FLAC__StreamMetadata_CueSheet *cs;
-
-	FLAC__ASSERT(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
-	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
-
-	cs = &object->data.cue_sheet;
-
-	/* free the track at track_num */
-	free(cs->tracks[track_num].indices);
-
-	/* move all tracks > track_num backward one space */
-	memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
-	cs->tracks[cs->num_tracks-1].num_indices = 0;
-	cs->tracks[cs->num_tracks-1].indices = 0;
-
-	return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
-}
-
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
-{
-	FLAC__ASSERT(object != NULL);
-	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(object != NULL);
-	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(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
-	FLAC__ASSERT(mime_type != NULL);
-
-	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;
-	}
-
-	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(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
-	FLAC__ASSERT(description != NULL);
-
-	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;
-	}
-
-	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(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
-	FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && 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;
-	}
-
-	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(object != NULL);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
-
-	return FLAC__format_picture_is_legal(&object->data.picture, violation);
-}
diff --git a/libFLAC/ogg_decoder_aspect.c b/libFLAC/ogg_decoder_aspect.c
deleted file mode 100644
index 40cee19..0000000
--- a/libFLAC/ogg_decoder_aspect.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec
- * Copyright (C) 2002-2009  Josh Coalson
- * Copyright (C) 2011-2016  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;
-}
diff --git a/libFLAC/ogg_encoder_aspect.c b/libFLAC/ogg_encoder_aspect.c
deleted file mode 100644
index ebd4614..0000000
--- a/libFLAC/ogg_encoder_aspect.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec
- * Copyright (C) 2002-2009  Josh Coalson
- * Copyright (C) 2011-2016  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;
-}
diff --git a/libFLAC/ogg_helper.c b/libFLAC/ogg_helper.c
deleted file mode 100644
index 7ca9160..0000000
--- a/libFLAC/ogg_helper.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec
- * Copyright (C) 2004-2009  Josh Coalson
- * Copyright (C) 2011-2016  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;
-}
diff --git a/libFLAC/ogg_mapping.c b/libFLAC/ogg_mapping.c
deleted file mode 100644
index 08fa514..0000000
--- a/libFLAC/ogg_mapping.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec
- * Copyright (C) 2004-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 */
diff --git a/libFLAC/stream_decoder.c b/libFLAC/stream_decoder.c
deleted file mode 100644
index 5d439eb..0000000
--- a/libFLAC/stream_decoder.c
+++ /dev/null
@@ -1,3408 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 <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/bitreader.h"
-#include "private/bitmath.h"
-#include "private/cpu.h"
-#include "private/crc.h"
-#include "private/fixed.h"
-#include "private/format.h"
-#include "private/lpc.h"
-#include "private/md5.h"
-#include "private/memory.h"
-#include "private/macros.h"
-
-
-/* technically this should be in an "export.c" but this is convenient enough */
-FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC = FLAC__HAS_OGG;
-
-
-/***********************************************************************
- *
- * Private static data
- *
- ***********************************************************************/
-
-static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
-
-/***********************************************************************
- *
- * Private class method prototypes
- *
- ***********************************************************************/
-
-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);
-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, 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);
-static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
-static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
-static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
-static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
-static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
-static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
-static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended);
-static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
-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);
-
-/***********************************************************************
- *
- * Private class data
- *
- ***********************************************************************/
-
-typedef struct FLAC__StreamDecoderPrivate {
-	FLAC__bool is_ogg;
-	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;
-	/* generic 32-bit datapath: */
-	void (*local_lpc_restore_signal)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
-	/* generic 64-bit datapath: */
-	void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
-	/* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */
-	void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
-	void *client_data;
-	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 fixed_block_size, next_fixed_block_size;
-	FLAC__uint64 samples_decoded;
-	FLAC__bool has_stream_info, has_seek_table;
-	FLAC__StreamMetadata stream_info;
-	FLAC__StreamMetadata seek_table;
-	FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */
-	FLAC__byte *metadata_filter_ids;
-	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;
-	FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */
-	FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */
-	/* unaligned (original) pointers to allocated data */
-	FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS];
-	FLAC__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 */
-	FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */
-} FLAC__StreamDecoderPrivate;
-
-/***********************************************************************
- *
- * Public static class data
- *
- ***********************************************************************/
-
-FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
-	"FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
-	"FLAC__STREAM_DECODER_READ_METADATA",
-	"FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
-	"FLAC__STREAM_DECODER_READ_FRAME",
-	"FLAC__STREAM_DECODER_END_OF_STREAM",
-	"FLAC__STREAM_DECODER_OGG_ERROR",
-	"FLAC__STREAM_DECODER_SEEK_ERROR",
-	"FLAC__STREAM_DECODER_ABORTED",
-	"FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
-	"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",
-	"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"
-};
-
-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_UNPARSEABLE_STREAM"
-};
-
-/***********************************************************************
- *
- * Class constructor/destructor
- *
- ***********************************************************************/
-FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
-{
-	FLAC__StreamDecoder *decoder;
-	unsigned i;
-
-	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
-
-	decoder = calloc(1, sizeof(FLAC__StreamDecoder));
-	if(decoder == 0) {
-		return 0;
-	}
-
-	decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected));
-	if(decoder->protected_ == 0) {
-		free(decoder);
-		return 0;
-	}
-
-	decoder->private_ = calloc(1, sizeof(FLAC__StreamDecoderPrivate));
-	if(decoder->private_ == 0) {
-		free(decoder->protected_);
-		free(decoder);
-		return 0;
-	}
-
-	decoder->private_->input = FLAC__bitreader_new();
-	if(decoder->private_->input == 0) {
-		free(decoder->private_);
-		free(decoder->protected_);
-		free(decoder);
-		return 0;
-	}
-
-	decoder->private_->metadata_filter_ids_capacity = 16;
-	if(0 == (decoder->private_->metadata_filter_ids = 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);
-		return 0;
-	}
-
-	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
-		decoder->private_->output[i] = 0;
-		decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
-	}
-
-	decoder->private_->output_capacity = 0;
-	decoder->private_->output_channels = 0;
-	decoder->private_->has_seek_table = false;
-
-	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
-
-	decoder->private_->file = 0;
-
-	set_defaults_(decoder);
-
-	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
-
-	return decoder;
-}
-
-FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
-{
-	unsigned i;
-
-	if (decoder == NULL)
-		return ;
-
-	FLAC__ASSERT(0 != decoder->protected_);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->private_->input);
-
-	(void)FLAC__stream_decoder_finish(decoder);
-
-	if(0 != decoder->private_->metadata_filter_ids)
-		free(decoder->private_->metadata_filter_ids);
-
-	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]);
-
-	free(decoder->private_);
-	free(decoder->protected_);
-	free(decoder);
-}
-
-/***********************************************************************
- *
- * Public class methods
- *
- ***********************************************************************/
-
-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 FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
-
-	if(FLAC__HAS_OGG == 0 && is_ogg)
-		return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
-
-	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;
-
-#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
-	 */
-	FLAC__cpu_info(&decoder->private_->cpuinfo);
-	/* first default to the non-asm routines */
-	decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
-	decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
-	decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
-	/* now override with asm where appropriate */
-#ifndef FLAC__NO_ASM
-	if(decoder->private_->cpuinfo.use_asm) {
-#ifdef FLAC__CPU_IA32
-		FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
-#ifdef FLAC__HAS_NASM
-		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;
-		}
-		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;
-		}
-#endif
-#if FLAC__HAS_X86INTRIN && ! defined FLAC__INTEGER_ONLY_LIBRARY
-# 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
-
-	/* from here on, errors are fatal */
-
-	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 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 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);
-
-	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__bitreader_free(decoder->private_->input);
-	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
-		/* WATCHOUT:
-		 * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
-		 * output arrays have a buffer of up to 3 zeroes in front
-		 * (at negative indices) for alignment purposes; we use 4
-		 * to keep the data well-aligned.
-		 */
-		if(0 != decoder->private_->output[i]) {
-			free(decoder->private_->output[i]-4);
-			decoder->private_->output[i] = 0;
-		}
-		if(0 != decoder->private_->residual_unaligned[i]) {
-			free(decoder->private_->residual_unaligned[i]);
-			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
-		}
-	}
-	decoder->private_->output_capacity = 0;
-	decoder->private_->output_channels = 0;
-
-#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;
-
-	return !md5_failed;
-}
-
-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_);
-	FLAC__ASSERT(0 != decoder->protected_);
-	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-#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_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-	decoder->protected_->md5_checking = value;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->protected_);
-	FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
-	/* double protection */
-	if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
-		return false;
-	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-	decoder->private_->metadata_filter[type] = true;
-	if(type == FLAC__METADATA_TYPE_APPLICATION)
-		decoder->private_->metadata_filter_ids_count = 0;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->protected_);
-	FLAC__ASSERT(0 != id);
-	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-
-	if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
-		return true;
-
-	FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
-
-	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
-		if(0 == (decoder->private_->metadata_filter_ids = 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;
-	}
-
-	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
-	decoder->private_->metadata_filter_ids_count++;
-
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
-{
-	unsigned i;
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->protected_);
-	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-	for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
-		decoder->private_->metadata_filter[i] = true;
-	decoder->private_->metadata_filter_ids_count = 0;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->protected_);
-	FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
-	/* double protection */
-	if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
-		return false;
-	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-	decoder->private_->metadata_filter[type] = false;
-	if(type == FLAC__METADATA_TYPE_APPLICATION)
-		decoder->private_->metadata_filter_ids_count = 0;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->protected_);
-	FLAC__ASSERT(0 != id);
-	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-
-	if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
-		return true;
-
-	FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
-
-	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
-		if(0 == (decoder->private_->metadata_filter_ids = 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;
-	}
-
-	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
-	decoder->private_->metadata_filter_ids_count++;
-
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->protected_);
-	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-	memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
-	decoder->private_->metadata_filter_ids_count = 0;
-	return true;
-}
-
-FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-	return decoder->protected_->state;
-}
-
-FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
-{
-	return FLAC__StreamDecoderStateString[decoder->protected_->state];
-}
-
-FLAC_API 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);
-	FLAC__ASSERT(0 != decoder->protected_);
-	return decoder->protected_->channels;
-}
-
-FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-	return decoder->protected_->channel_assignment;
-}
-
-FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-	return decoder->protected_->bits_per_sample;
-}
-
-FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-	return decoder->protected_->sample_rate;
-}
-
-FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-	return decoder->protected_->blocksize;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_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 && decoder->private_->is_ogg)
-		return false;
-
-	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);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->protected_);
-
-	if(!decoder->private_->internal_reset_hack && decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
-		return false;
-
-	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;
-	}
-	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->private_);
-	FLAC__ASSERT(0 != decoder->protected_);
-
-	if(!FLAC__stream_decoder_flush(decoder)) {
-		/* 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_->has_stream_info = false;
-
-	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;
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
-{
-	FLAC__bool got_a_frame;
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-
-	while(1) {
-		switch(decoder->protected_->state) {
-			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
-				if(!find_metadata_(decoder))
-					return false; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_READ_METADATA:
-				if(!read_metadata_(decoder))
-					return false; /* above function sets the status for us */
-				else
-					return true;
-			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
-				if(!frame_sync_(decoder))
-					return true; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_READ_FRAME:
-				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
-					return false; /* above function sets the status for us */
-				if(got_a_frame)
-					return true; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_END_OF_STREAM:
-			case FLAC__STREAM_DECODER_ABORTED:
-				return true;
-			default:
-				FLAC__ASSERT(0);
-				return false;
-		}
-	}
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-
-	while(1) {
-		switch(decoder->protected_->state) {
-			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
-				if(!find_metadata_(decoder))
-					return false; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_READ_METADATA:
-				if(!read_metadata_(decoder))
-					return false; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
-			case FLAC__STREAM_DECODER_READ_FRAME:
-			case FLAC__STREAM_DECODER_END_OF_STREAM:
-			case FLAC__STREAM_DECODER_ABORTED:
-				return true;
-			default:
-				FLAC__ASSERT(0);
-				return false;
-		}
-	}
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
-{
-	FLAC__bool dummy;
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-
-	while(1) {
-		switch(decoder->protected_->state) {
-			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
-				if(!find_metadata_(decoder))
-					return false; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_READ_METADATA:
-				if(!read_metadata_(decoder))
-					return false; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
-				if(!frame_sync_(decoder))
-					return true; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_READ_FRAME:
-				if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
-					return false; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_END_OF_STREAM:
-			case FLAC__STREAM_DECODER_ABORTED:
-				return true;
-			default:
-				FLAC__ASSERT(0);
-				return false;
-		}
-	}
-}
-
-FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
-{
-	FLAC__bool got_a_frame;
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->protected_);
-
-	while(1) {
-		switch(decoder->protected_->state) {
-			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
-			case FLAC__STREAM_DECODER_READ_METADATA:
-				return false; /* above function sets the status for us */
-			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
-				if(!frame_sync_(decoder))
-					return true; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_READ_FRAME:
-				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
-					return false; /* above function sets the status for us */
-				if(got_a_frame)
-					return true; /* above function sets the status for us */
-				break;
-			case FLAC__STREAM_DECODER_END_OF_STREAM:
-			case FLAC__STREAM_DECODER_ABORTED:
-				return true;
-			default:
-				FLAC__ASSERT(0);
-				return false;
-		}
-	}
-}
-
-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
- *
- ***********************************************************************/
-
-unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
-{
-	FLAC__ASSERT(0 != decoder);
-	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;
-}
-
-/***********************************************************************
- *
- * Private class methods
- *
- ***********************************************************************/
-
-void set_defaults_(FLAC__StreamDecoder *decoder)
-{
-	decoder->private_->is_ogg = false;
-	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;
-
-	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;
-	FLAC__int32 *tmp;
-
-	if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
-		return true;
-
-	/* simply using realloc() is not practical because the number of channels may change mid-stream */
-
-	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
-		if(0 != decoder->private_->output[i]) {
-			free(decoder->private_->output[i]-4);
-			decoder->private_->output[i] = 0;
-		}
-		if(0 != decoder->private_->residual_unaligned[i]) {
-			free(decoder->private_->residual_unaligned[i]);
-			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
-		}
-	}
-
-	for(i = 0; i < channels; i++) {
-		/* WATCHOUT:
-		 * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
-		 * output arrays have a buffer of up to 3 zeroes in front
-		 * (at negative indices) for alignment purposes; we use 4
-		 * to keep the data well-aligned.
-		 */
-		tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/);
-		if(tmp == 0) {
-			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
-			return false;
-		}
-		memset(tmp, 0, sizeof(FLAC__int32)*4);
-		decoder->private_->output[i] = tmp + 4;
-
-		if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) {
-			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
-			return false;
-		}
-	}
-
-	decoder->private_->output_capacity = size;
-	decoder->private_->output_channels = channels;
-
-	return true;
-}
-
-FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
-{
-	size_t i;
-
-	FLAC__ASSERT(0 != decoder);
-	FLAC__ASSERT(0 != decoder->private_);
-
-	for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
-		if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
-			return true;
-
-	return false;
-}
-
-FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
-{
-	FLAC__uint32 x;
-	unsigned i, id;
-	FLAC__bool first = true;
-
-	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
-
-	for(i = id = 0; i < 4; ) {
-		if(decoder->private_->cached) {
-			x = (FLAC__uint32)decoder->private_->lookahead;
-			decoder->private_->cached = false;
-		}
-		else {
-			if(!FLAC__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;
-			i++;
-			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; /* 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__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 */
-			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
-				decoder->private_->lookahead = (FLAC__byte)x;
-				decoder->private_->cached = true;
-			}
-			else if(x >> 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;
-			}
-		}
-		i = 0;
-		if(first) {
-			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
-			first = false;
-		}
-	}
-
-	decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
-	return true;
-}
-
-FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
-{
-	FLAC__bool is_last;
-	FLAC__uint32 i, x, type, length;
-
-	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
-
-	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__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN))
-		return false; /* 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))
-			return false;
-
-		decoder->private_->has_stream_info = true;
-		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) {
-		/* just in case we already have a seek table, and reading the next one fails: */
-		decoder->private_->has_seek_table = false;
-
-		if(!read_metadata_seektable_(decoder, is_last, length))
-			return false;
-
-		decoder->private_->has_seek_table = true;
-		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 {
-		FLAC__bool skip_it = !decoder->private_->metadata_filter[type];
-		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__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))
-				skip_it = !skip_it;
-		}
-
-		if(skip_it) {
-			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__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 = malloc(real_length))) {
-							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
-							ok = false;
-						}
-						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, real_length))
-						ok = false;
-					break;
-				case FLAC__METADATA_TYPE_CUESHEET:
-					if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
-						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);
-					break;
-				default:
-					if(real_length > 0) {
-						if(0 == (block.data.unknown.data = malloc(real_length))) {
-							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
-							ok = false;
-						}
-						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;
-			}
-			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 */
-			switch(type) {
-				case FLAC__METADATA_TYPE_PADDING:
-					break;
-				case FLAC__METADATA_TYPE_APPLICATION:
-					if(0 != block.data.application.data)
-						free(block.data.application.data);
-					break;
-				case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-					if(0 != block.data.vorbis_comment.vendor_string.entry)
-						free(block.data.vorbis_comment.vendor_string.entry);
-					if(block.data.vorbis_comment.num_comments > 0)
-						for(i = 0; i < block.data.vorbis_comment.num_comments; i++)
-							if(0 != block.data.vorbis_comment.comments[i].entry)
-								free(block.data.vorbis_comment.comments[i].entry);
-					if(0 != block.data.vorbis_comment.comments)
-						free(block.data.vorbis_comment.comments);
-					break;
-				case FLAC__METADATA_TYPE_CUESHEET:
-					if(block.data.cue_sheet.num_tracks > 0)
-						for(i = 0; i < block.data.cue_sheet.num_tracks; i++)
-							if(0 != block.data.cue_sheet.tracks[i].indices)
-								free(block.data.cue_sheet.tracks[i].indices);
-					if(0 != block.data.cue_sheet.tracks)
-						free(block.data.cue_sheet.tracks);
-					break;
-				case FLAC__METADATA_TYPE_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);
-				default:
-					if(0 != block.data.unknown.data)
-						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 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;
-}
-
-FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length)
-{
-	FLAC__uint32 x;
-	unsigned bits, used_bits = 0;
-
-	FLAC__ASSERT(FLAC__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;
-	decoder->private_->stream_info.length = length;
-
-	bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN;
-	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__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__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__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__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__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__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__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__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);
-	if (length < (used_bits / 8))
-		return false; /* read_callback_ sets the state for us */
-	length -= (used_bits / 8);
-	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_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length)
-{
-	FLAC__uint32 i, x;
-	FLAC__uint64 xx;
-
-	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;
-	decoder->private_->seek_table.length = length;
-
-	decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
-
-	/* use realloc since we may pass through here several times (e.g. after seeking) */
-	if(0 == (decoder->private_->seek_table.data.seek_table.points = 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__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__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__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 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, unsigned length)
-{
-	FLAC__uint32 i;
-
-	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
-
-	/* read vendor string */
-	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';
-		}
-		else
-			obj->vendor_string.entry = 0;
-
-		/* 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 > 100000) {
-			/* Possibly malicious file. */
-			obj->num_comments = 0;
-			return false;
-		}
-		if (obj->num_comments > 0) {
-			if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
-				obj->num_comments = 0;
-				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
-				return false;
-			}
-			for (i = 0; i < obj->num_comments; i++) {
-				/* Initialize here just to make sure. */
-				obj->comments[i].length = 0;
-				obj->comments[i].entry = 0;
-
-				FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
-				if (length < 4) {
-					obj->num_comments = i;
-					goto skip;
-				}
-				else
-					length -= 4;
-				if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) {
-					obj->num_comments = i;
-					return false; /* read_callback_ sets the state for us */
-				}
-				if (obj->comments[i].length > 0) {
-					if (length < obj->comments[i].length) {
-						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;
-						obj->num_comments = i;
-						return false;
-					}
-					memset (obj->comments[i].entry, 0, obj->comments[i].length) ;
-					if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) {
-						/* Current i-th entry is bad, so we delete it. */
-						free (obj->comments[i].entry) ;
-						obj->comments[i].entry = NULL ;
-						obj->num_comments = i;
-						goto skip;
-					}
-					obj->comments[i].entry[obj->comments[i].length] = '\0';
-				}
-				else
-					obj->comments[i].entry = 0;
-			}
-		}
-	}
-
-  skip:
-	if (length > 0) {
-		/* length > 0 can only happen on files with invalid data in comments */
-		if(obj->num_comments < 1) {
-			free(obj->comments);
-			obj->comments = NULL;
-		}
-		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_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj)
-{
-	FLAC__uint32 i, j, x;
-
-	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__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__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__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__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__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 = 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__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__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__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__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__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__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__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 = 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 *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__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__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
-						return false; /* read_callback_ sets the state for us */
-				}
-			}
-		}
-	}
-
-	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;
-	unsigned i, skip;
-
-	/* skip the version and flags bytes */
-	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__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__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip))
-		return false; /* read_callback_ sets the state for us */
-	return true;
-}
-
-FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder)
-{
-	FLAC__uint32 x;
-	FLAC__bool first = true;
-
-	/* If we know the total number of samples in the stream, stop if we've read that many. */
-	/* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */
-	if(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;
-		}
-	}
-
-	/* make sure we're byte aligned */
-	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) {
-		if(decoder->private_->cached) {
-			x = (FLAC__uint32)decoder->private_->lookahead;
-			decoder->private_->cached = false;
-		}
-		else {
-			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__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 */
-			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
-				decoder->private_->lookahead = (FLAC__byte)x;
-				decoder->private_->cached = true;
-			}
-			else if(x >> 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;
-			}
-		}
-		if(first) {
-			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
-			first = false;
-		}
-	}
-
-	return true;
-}
-
-FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode)
-{
-	unsigned channel;
-	unsigned i;
-	FLAC__int32 mid, side;
-	unsigned frame_crc; /* the one we calculate from the input stream */
-	FLAC__uint32 x;
-
-	*got_a_frame = false;
-
-	/* init the CRC */
-	frame_crc = 0;
-	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) /* 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;
-	for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
-		/*
-		 * first figure the correct bits-per-sample of the subframe
-		 */
-		unsigned bps = decoder->private_->frame.header.bits_per_sample;
-		switch(decoder->private_->frame.header.channel_assignment) {
-			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
-				/* no adjustment needed */
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
-				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-				if(channel == 1)
-					bps++;
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
-				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-				if(channel == 0)
-					bps++;
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
-				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-				if(channel == 1)
-					bps++;
-				break;
-			default:
-				FLAC__ASSERT(0);
-		}
-		/*
-		 * now read it
-		 */
-		if(!read_subframe_(decoder, channel, bps, do_full_decode))
-			return false;
-		if(decoder->protected_->state == FLAC__STREAM_DECODER_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__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) {
-				case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
-					/* do nothing */
-					break;
-				case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
-					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-					for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
-						decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
-					break;
-				case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
-					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-					for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
-						decoder->private_->output[0][i] += decoder->private_->output[1][i];
-					break;
-				case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
-					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-					for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
-#if 1
-						mid = decoder->private_->output[0][i];
-						side = decoder->private_->output[1][i];
-						mid = ((uint32_t) mid) << 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:
-					FLAC__ASSERT(0);
-					break;
-			}
-		}
-	}
-	else {
-		/* Bad frame, emit error and zero the output signal */
-		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);
-			}
-		}
-	}
-
-	*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;
-	decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample;
-	decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate;
-	decoder->protected_->blocksize = decoder->private_->frame.header.blocksize;
-
-	FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
-	decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
-
-	/* write it */
-	if(do_full_decode) {
-		if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) {
-			decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
-			return false;
-		}
-	}
-
-	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-	return true;
-}
-
-FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder)
-{
-	FLAC__uint32 x;
-	FLAC__uint64 xx;
-	unsigned i, blocksize_hint = 0, sample_rate_hint = 0;
-	FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */
-	unsigned raw_header_len;
-	FLAC__bool is_unparseable = false;
-
-	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];
-	raw_header[1] = decoder->private_->header_warmup[1];
-	raw_header_len = 2;
-
-	/* 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.
-	 */
-
-	/*
-	 * 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__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;
-			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
-			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-			return true;
-		}
-		raw_header[raw_header_len++] = (FLAC__byte)x;
-	}
-
-	switch(x = raw_header[2] >> 4) {
-		case 0:
-			is_unparseable = true;
-			break;
-		case 1:
-			decoder->private_->frame.header.blocksize = 192;
-			break;
-		case 2:
-		case 3:
-		case 4:
-		case 5:
-			decoder->private_->frame.header.blocksize = 576 << (x-2);
-			break;
-		case 6:
-		case 7:
-			blocksize_hint = x;
-			break;
-		case 8:
-		case 9:
-		case 10:
-		case 11:
-		case 12:
-		case 13:
-		case 14:
-		case 15:
-			decoder->private_->frame.header.blocksize = 256 << (x-8);
-			break;
-		default:
-			FLAC__ASSERT(0);
-			break;
-	}
-
-	switch(x = raw_header[2] & 0x0f) {
-		case 0:
-			if(decoder->private_->has_stream_info)
-				decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate;
-			else
-				is_unparseable = true;
-			break;
-		case 1:
-			decoder->private_->frame.header.sample_rate = 88200;
-			break;
-		case 2:
-			decoder->private_->frame.header.sample_rate = 176400;
-			break;
-		case 3:
-			decoder->private_->frame.header.sample_rate = 192000;
-			break;
-		case 4:
-			decoder->private_->frame.header.sample_rate = 8000;
-			break;
-		case 5:
-			decoder->private_->frame.header.sample_rate = 16000;
-			break;
-		case 6:
-			decoder->private_->frame.header.sample_rate = 22050;
-			break;
-		case 7:
-			decoder->private_->frame.header.sample_rate = 24000;
-			break;
-		case 8:
-			decoder->private_->frame.header.sample_rate = 32000;
-			break;
-		case 9:
-			decoder->private_->frame.header.sample_rate = 44100;
-			break;
-		case 10:
-			decoder->private_->frame.header.sample_rate = 48000;
-			break;
-		case 11:
-			decoder->private_->frame.header.sample_rate = 96000;
-			break;
-		case 12:
-		case 13:
-		case 14:
-			sample_rate_hint = x;
-			break;
-		case 15:
-			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:
-			FLAC__ASSERT(0);
-	}
-
-	x = (unsigned)(raw_header[3] >> 4);
-	if(x & 8) {
-		decoder->private_->frame.header.channels = 2;
-		switch(x & 7) {
-			case 0:
-				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
-				break;
-			case 1:
-				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
-				break;
-			case 2:
-				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
-				break;
-			default:
-				is_unparseable = true;
-				break;
-		}
-	}
-	else {
-		decoder->private_->frame.header.channels = (unsigned)x + 1;
-		decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
-	}
-
-	switch(x = (unsigned)(raw_header[3] & 0x0e) >> 1) {
-		case 0:
-			if(decoder->private_->has_stream_info)
-				decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample;
-			else
-				is_unparseable = true;
-			break;
-		case 1:
-			decoder->private_->frame.header.bits_per_sample = 8;
-			break;
-		case 2:
-			decoder->private_->frame.header.bits_per_sample = 12;
-			break;
-		case 4:
-			decoder->private_->frame.header.bits_per_sample = 16;
-			break;
-		case 5:
-			decoder->private_->frame.header.bits_per_sample = 20;
-			break;
-		case 6:
-			decoder->private_->frame.header.bits_per_sample = 24;
-			break;
-		case 3:
-		case 7:
-			is_unparseable = true;
-			break;
-		default:
-			FLAC__ASSERT(0);
-			break;
-	}
-
-	/* check to make sure that reserved bit is 0 */
-	if(raw_header[3] & 0x01) /* MAGIC NUMBER */
-		is_unparseable = true;
-
-	/* 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;
-			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_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
-		decoder->private_->frame.header.number.sample_number = xx;
-	}
-	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;
-			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_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
-		decoder->private_->frame.header.number.frame_number = x;
-	}
-
-	if(blocksize_hint) {
-		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__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;
-		}
-		decoder->private_->frame.header.blocksize = x+1;
-	}
-
-	if(sample_rate_hint) {
-		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__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;
-		}
-		if(sample_rate_hint == 12)
-			decoder->private_->frame.header.sample_rate = x*1000;
-		else if(sample_rate_hint == 13)
-			decoder->private_->frame.header.sample_rate = x;
-		else
-			decoder->private_->frame.header.sample_rate = x*10;
-	}
-
-	/* read the CRC-8 byte */
-	if(!FLAC__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) {
-		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) {
-		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;
-}
-
-FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
-{
-	FLAC__uint32 x;
-	FLAC__bool wasted_bits;
-	unsigned i;
-
-	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;
-
-	if(wasted_bits) {
-		unsigned u;
-		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;
-		if (decoder->private_->frame.subframes[channel].wasted_bits >= bps)
-			return false;
-		bps -= decoder->private_->frame.subframes[channel].wasted_bits;
-	}
-	else
-		decoder->private_->frame.subframes[channel].wasted_bits = 0;
-
-	/*
-	 * Lots of magic numbers here
-	 */
-	if(x & 0x80) {
-		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
-		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-		return true;
-	}
-	else if(x == 0) {
-		if(!read_subframe_constant_(decoder, channel, bps, do_full_decode))
-			return false;
-	}
-	else if(x == 2) {
-		if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode))
-			return false;
-	}
-	else if(x < 16) {
-		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) {
-		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) {
-		x = decoder->private_->frame.subframes[channel].wasted_bits;
-		for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
-			uint32_t val = decoder->private_->output[channel][i];
-			decoder->private_->output[channel][i] = (val << x);
-		}
-	}
-
-	return true;
-}
-
-FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
-{
-	FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
-	FLAC__int32 x;
-	unsigned i;
-	FLAC__int32 *output = decoder->private_->output[channel];
-
-	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
-
-	if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
-		return false; /* read_callback_ sets the state for us */
-
-	subframe->value = x;
-
-	/* decode the subframe */
-	if(do_full_decode) {
-		for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
-			output[i] = x;
-	}
-
-	return true;
-}
-
-FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
-{
-	FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
-	FLAC__int32 i32;
-	FLAC__uint32 u32;
-	unsigned u;
-
-	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED;
-
-	subframe->residual = decoder->private_->residual[channel];
-	subframe->order = order;
-
-	/* read warm-up samples */
-	for(u = 0; u < order; u++) {
-		if(!FLAC__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__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:
-		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 */
-			if(decoder->private_->frame.header.blocksize >> u32 < order) {
-				send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
-				decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-				return true;
-			}
-			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:
-			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:
-		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:
-			FLAC__ASSERT(0);
-	}
-
-	/* decode the subframe */
-	if(do_full_decode) {
-		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
-		FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
-	}
-
-	return true;
-}
-
-FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
-{
-	FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
-	FLAC__int32 i32;
-	FLAC__uint32 u32;
-	unsigned u;
-
-	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC;
-
-	subframe->residual = decoder->private_->residual[channel];
-	subframe->order = order;
-
-	/* read warm-up samples */
-	for(u = 0; u < order; u++) {
-		if(!FLAC__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__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) {
-		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
-		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-		return true;
-	}
-	subframe->qlp_coeff_precision = u32+1;
-
-	/* read qlp shift */
-	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 */
-	if(i32 < 0) {
-		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
-		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-		return true;
-	}
-	subframe->quantization_level = i32;
-
-	/* read quantized lp coefficiencts */
-	for(u = 0; u < order; u++) {
-		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__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:
-		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 */
-			if(decoder->private_->frame.header.blocksize >> u32 < order) {
-				send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
-				decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-				return true;
-			}
-			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:
-			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:
-		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:
-			FLAC__ASSERT(0);
-	}
-
-	/* decode the subframe */
-	if(do_full_decode) {
-		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
-		if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
-			if(bps <= 16 && subframe->qlp_coeff_precision <= 16)
-				decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
-			else
-				decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
-		else
-			decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
-	}
-
-	return true;
-}
-
-FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
-{
-	FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
-	FLAC__int32 x, *residual = decoder->private_->residual[channel];
-	unsigned i;
-
-	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
-
-	subframe->data = residual;
-
-	for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
-		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
-			return false; /* read_callback_ sets the state for us */
-		residual[i] = x;
-	}
-
-	/* decode the subframe */
-	if(do_full_decode)
-		memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
-
-	return true;
-}
-
-FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended)
-{
-	FLAC__uint32 rice_parameter;
-	int i;
-	unsigned partition, sample, u;
-	const unsigned partitions = 1u << partition_order;
-	const unsigned partition_samples = partition_order > 0? decoder->private_->frame.header.blocksize >> partition_order : decoder->private_->frame.header.blocksize - predictor_order;
-	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;
-
-	/* invalid predictor and partition orders mush be handled in the callers */
-	FLAC__ASSERT(partition_order > 0? partition_samples >= predictor_order : decoder->private_->frame.header.blocksize >= predictor_order);
-
-	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;
-	}
-
-	sample = 0;
-	for(partition = 0; partition < partitions; partition++) {
-		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 < pesc) {
-			partitioned_rice_contents->raw_bits[partition] = 0;
-			u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order;
-			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;
-		}
-		else {
-			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__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
-					return false; /* read_callback_ sets the state for us */
-				residual[sample] = i;
-			}
-		}
-	}
-
-	return true;
-}
-
-FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder)
-{
-	if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
-		FLAC__uint32 zero = 0;
-		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) {
-			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
-			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
-		}
-	}
-	return true;
-}
-
-FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data)
-{
-	FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data;
-
-	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;
-		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 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)((double)(target_sample - lower_bound_sample) / (double)(upper_bound_sample - lower_bound_sample) * (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 */
-			FLAC__uint64 sample_range_16 = (upper_bound_sample - lower_bound_sample) >> 16;
-			if (sample_range_16 == 0) sample_range_16 = 1; // avoid divide by 0
-			pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) >> 8) * ((upper_bound - lower_bound) >> 8) / sample_range_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_ABORTED) {
-			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)((double)(target_sample - left_sample) / (double)(right_sample - left_sample) * (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_ABORTED) {
-			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;
-}
diff --git a/libFLAC/stream_encoder.c b/libFLAC/stream_encoder.c
deleted file mode 100644
index b0b2650..0000000
--- a/libFLAC/stream_encoder.c
+++ /dev/null
@@ -1,4551 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 <limits.h>
-#include <stdio.h>
-#include <stdlib.h> /* for malloc() */
-#include <string.h> /* for memcpy() */
-#include <sys/types.h> /* for off_t */
-#ifdef _WIN32
-#include <windows.h> /* for GetFileType() */
-#include <io.h> /* for _get_osfhandle() */
-#endif
-#include "share/compat.h"
-#include "FLAC/assert.h"
-#include "FLAC/stream_decoder.h"
-#include "protected/stream_encoder.h"
-#include "private/bitwriter.h"
-#include "private/bitmath.h"
-#include "private/crc.h"
-#include "private/cpu.h"
-#include "private/fixed.h"
-#include "private/format.h"
-#include "private/lpc.h"
-#include "private/md5.h"
-#include "private/memory.h"
-#include "private/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"
-
-
-/* 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
-
-
-typedef struct {
-	FLAC__int32 *data[FLAC__MAX_CHANNELS];
-	unsigned size; /* of each data[] in samples */
-	unsigned tail;
-} verify_input_fifo;
-
-typedef struct {
-	const FLAC__byte *data;
-	unsigned capacity;
-	unsigned bytes;
-} verify_output;
-
-typedef enum {
-	ENCODER_IN_MAGIC = 0,
-	ENCODER_IN_METADATA = 1,
-	ENCODER_IN_AUDIO = 2
-} EncoderStateHint;
-
-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
- *
- ***********************************************************************/
-
-static void set_defaults_(FLAC__StreamEncoder *encoder);
-static void free_(FLAC__StreamEncoder *encoder);
-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,
-	const FLAC__FrameHeader *frame_header,
-	unsigned subframe_bps,
-	const FLAC__int32 integer_signal[],
-	FLAC__Subframe *subframe[2],
-	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
-	FLAC__int32 *residual[2],
-	unsigned *best_subframe,
-	unsigned *best_bits
-);
-
-static FLAC__bool add_subframe_(
-	FLAC__StreamEncoder *encoder,
-	unsigned blocksize,
-	unsigned subframe_bps,
-	const FLAC__Subframe *subframe,
-	FLAC__BitWriter *frame
-);
-
-static unsigned evaluate_constant_subframe_(
-	FLAC__StreamEncoder *encoder,
-	const FLAC__int32 signal,
-	unsigned blocksize,
-	unsigned subframe_bps,
-	FLAC__Subframe *subframe
-);
-
-static unsigned evaluate_fixed_subframe_(
-	FLAC__StreamEncoder *encoder,
-	const FLAC__int32 signal[],
-	FLAC__int32 residual[],
-	FLAC__uint64 abs_residual_partition_sums[],
-	unsigned raw_bits_per_partition[],
-	unsigned blocksize,
-	unsigned subframe_bps,
-	unsigned order,
-	unsigned rice_parameter,
-	unsigned rice_parameter_limit,
-	unsigned min_partition_order,
-	unsigned max_partition_order,
-	FLAC__bool do_escape_coding,
-	unsigned rice_parameter_search_dist,
-	FLAC__Subframe *subframe,
-	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__uint64 abs_residual_partition_sums[],
-	unsigned raw_bits_per_partition[],
-	const FLAC__real lp_coeff[],
-	unsigned blocksize,
-	unsigned subframe_bps,
-	unsigned order,
-	unsigned qlp_coeff_precision,
-	unsigned rice_parameter,
-	unsigned rice_parameter_limit,
-	unsigned min_partition_order,
-	unsigned max_partition_order,
-	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,
-	FLAC__Subframe *subframe
-);
-
-static unsigned find_best_partition_order_(
-	struct FLAC__StreamEncoderPrivate *private_,
-	const FLAC__int32 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,
-	unsigned bps,
-	FLAC__bool do_escape_coding,
-	unsigned rice_parameter_search_dist,
-	FLAC__EntropyCodingMethod *best_ecm
-);
-
-static void 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
-);
-
-static void precompute_partition_info_escapes_(
-	const FLAC__int32 residual[],
-	unsigned raw_bits_per_partition[],
-	unsigned residual_samples,
-	unsigned predictor_order,
-	unsigned min_partition_order,
-	unsigned max_partition_order
-);
-
-static 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,
-	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
-	unsigned *bits
-);
-
-static unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples);
-
-/* verify-related routines: */
-static void append_to_verify_fifo_(
-	verify_input_fifo *fifo,
-	const FLAC__int32 * const input[],
-	unsigned input_offset,
-	unsigned channels,
-	unsigned wide_samples
-);
-
-static void append_to_verify_fifo_interleaved_(
-	verify_input_fifo *fifo,
-	const FLAC__int32 input[],
-	unsigned input_offset,
-	unsigned channels,
-	unsigned wide_samples
-);
-
-static FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], 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__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);
-
-
-/***********************************************************************
- *
- * Private class data
- *
- ***********************************************************************/
-
-typedef struct FLAC__StreamEncoderPrivate {
-	unsigned input_capacity;                          /* current size (in samples) of the signal and residual buffers */
-	FLAC__int32 *integer_signal[FLAC__MAX_CHANNELS];  /* the integer version of the input signal */
-	FLAC__int32 *integer_signal_mid_side[2];          /* the integer version of the mid-side input signal (stereo only) */
-#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 */
-	FLAC__int32 *residual_workspace_mid_side[2][2];
-	FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2];
-	FLAC__Subframe subframe_workspace_mid_side[2][2];
-	FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2];
-	FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2];
-	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2];
-	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2];
-	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2];
-	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2];
-	unsigned best_subframe[FLAC__MAX_CHANNELS];       /* index (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__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__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 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;
-	FLAC__MD5Context md5context;
-	FLAC__CPUInfo cpuinfo;
-	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, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
-	unsigned (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], unsigned data_len, 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[]);
-#endif
-	FLAC__bool disable_constant_subframes;
-	FLAC__bool disable_fixed_subframes;
-	FLAC__bool disable_verbatim_subframes;
-	FLAC__bool is_ogg;
-	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];
-#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__uint64 *abs_residual_partition_sums_unaligned;
-	unsigned *raw_bits_per_partition_unaligned;
-	/*
-	 * These fields have been moved here from private function local
-	 * declarations merely to save stack space during encoding.
-	 */
-#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
-	 */
-	struct {
-		FLAC__StreamDecoder *decoder;
-		EncoderStateHint state_hint;
-		FLAC__bool needs_magic_hack;
-		verify_input_fifo input_fifo;
-		verify_output output;
-		struct {
-			FLAC__uint64 absolute_sample;
-			unsigned frame_number;
-			unsigned channel;
-			unsigned sample;
-			FLAC__int32 expected;
-			FLAC__int32 got;
-		} error_stats;
-	} verify;
-	FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */
-} FLAC__StreamEncoderPrivate;
-
-/***********************************************************************
- *
- * Public static class data
- *
- ***********************************************************************/
-
-FLAC_API const char * const FLAC__StreamEncoderStateString[] = {
-	"FLAC__STREAM_ENCODER_OK",
-	"FLAC__STREAM_ENCODER_UNINITIALIZED",
-	"FLAC__STREAM_ENCODER_OGG_ERROR",
-	"FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR",
-	"FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA",
-	"FLAC__STREAM_ENCODER_CLIENT_ERROR",
-	"FLAC__STREAM_ENCODER_IO_ERROR",
-	"FLAC__STREAM_ENCODER_FRAMING_ERROR",
-	"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_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
- *
- */
-FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void)
-{
-	FLAC__StreamEncoder *encoder;
-	unsigned i;
-
-	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
-
-	encoder = calloc(1, sizeof(FLAC__StreamEncoder));
-	if(encoder == 0) {
-		return 0;
-	}
-
-	encoder->protected_ = calloc(1, sizeof(FLAC__StreamEncoderProtected));
-	if(encoder->protected_ == 0) {
-		free(encoder);
-		return 0;
-	}
-
-	encoder->private_ = calloc(1, sizeof(FLAC__StreamEncoderPrivate));
-	if(encoder->private_ == 0) {
-		free(encoder->protected_);
-		free(encoder);
-		return 0;
-	}
-
-	encoder->private_->frame = FLAC__bitwriter_new();
-	if(encoder->private_->frame == 0) {
-		free(encoder->private_);
-		free(encoder->protected_);
-		free(encoder);
-		return 0;
-	}
-
-	encoder->private_->file = 0;
-
-	set_defaults_(encoder);
-
-	encoder->private_->is_being_deleted = false;
-
-	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
-		encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0];
-		encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1];
-	}
-	for(i = 0; i < 2; i++) {
-		encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0];
-		encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1];
-	}
-	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
-		encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0];
-		encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1];
-	}
-	for(i = 0; i < 2; i++) {
-		encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0];
-		encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1];
-	}
-
-	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
-	}
-	for(i = 0; i < 2; i++) {
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
-	}
-	for(i = 0; i < 2; i++)
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]);
-
-	encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
-
-	return encoder;
-}
-
-FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder)
-{
-	unsigned i;
-
-	if (encoder == NULL)
-		return ;
-
-	FLAC__ASSERT(0 != encoder->protected_);
-	FLAC__ASSERT(0 != encoder->private_);
-	FLAC__ASSERT(0 != encoder->private_->frame);
-
-	encoder->private_->is_being_deleted = true;
-
-	(void)FLAC__stream_encoder_finish(encoder);
-
-	if(0 != encoder->private_->verify.decoder)
-		FLAC__stream_decoder_delete(encoder->private_->verify.decoder);
-
-	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
-	}
-	for(i = 0; i < 2; i++) {
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
-	}
-	for(i = 0; i < 2; i++)
-		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]);
-
-	FLAC__bitwriter_delete(encoder->private_->frame);
-	free(encoder->private_);
-	free(encoder->protected_);
-	free(encoder);
-}
-
-/***********************************************************************
- *
- * Public class methods
- *
- ***********************************************************************/
-
-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, metadata_picture_has_type1, metadata_picture_has_type2;
-
-	FLAC__ASSERT(0 != encoder);
-
-	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
-		return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
-
-	if(FLAC__HAS_OGG == 0 && is_ogg)
-		return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
-
-	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 FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS;
-
-	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_->bits_per_sample >= 32)
-		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 FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE;
-
-	if(!FLAC__format_sample_rate_is_valid(encoder->protected_->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 FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE;
-
-	if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER)
-		return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER;
-
-	if(encoder->protected_->blocksize < encoder->protected_->max_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 = 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)
-				encoder->protected_->qlp_coeff_precision = 7;
-			else if(encoder->protected_->blocksize <= 384)
-				encoder->protected_->qlp_coeff_precision = 8;
-			else if(encoder->protected_->blocksize <= 576)
-				encoder->protected_->qlp_coeff_precision = 9;
-			else if(encoder->protected_->blocksize <= 1152)
-				encoder->protected_->qlp_coeff_precision = 10;
-			else if(encoder->protected_->blocksize <= 2304)
-				encoder->protected_->qlp_coeff_precision = 11;
-			else if(encoder->protected_->blocksize <= 4608)
-				encoder->protected_->qlp_coeff_precision = 12;
-			else
-				encoder->protected_->qlp_coeff_precision = 13;
-		}
-		else {
-			if(encoder->protected_->blocksize <= 384)
-				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2;
-			else if(encoder->protected_->blocksize <= 1152)
-				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1;
-			else
-				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
-		}
-		FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION);
-	}
-	else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION)
-		return 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_->bits_per_sample != 8 &&
-			encoder->protected_->bits_per_sample != 12 &&
-			encoder->protected_->bits_per_sample != 16 &&
-			encoder->protected_->bits_per_sample != 20 &&
-			encoder->protected_->bits_per_sample != 24
-		)
-			return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
-		if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER)
-			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))
-		encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1;
-	if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order)
-		encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order;
-
-#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 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++) {
-		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 FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
-			metadata_has_seektable = true;
-			if(!FLAC__format_seektable_is_legal(&m->data.seek_table))
-				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
-		}
-		else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
-			if(metadata_has_vorbis_comment) /* only one is allowed */
-				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
-			metadata_has_vorbis_comment = true;
-		}
-		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;
-		encoder->private_->best_subframe[i] = 0;
-	}
-	for(i = 0; i < 2; i++) {
-		encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0;
-		encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0;
-		encoder->private_->best_subframe_mid_side[i] = 0;
-	}
-	encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0;
-	encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0;
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-	encoder->private_->loose_mid_side_stereo_frames = (unsigned)((double)encoder->protected_->sample_rate * 0.4 / (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;
-	encoder->private_->current_sample_number = 0;
-	encoder->private_->current_frame_number = 0;
-
-	/*
-	 * get the CPU info and set the function pointers
-	 */
-	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__INTEGER_ONLY_LIBRARY
-# ifndef FLAC__NO_ASM
-	if(encoder->private_->cpuinfo.use_asm) {
-#  ifdef FLAC__CPU_IA32
-		FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
-#   ifdef FLAC__HAS_NASM
-		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_old;
-			else if(encoder->protected_->max_lpc_order < 8)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old;
-			else if(encoder->protected_->max_lpc_order < 12)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old;
-			else if(encoder->protected_->max_lpc_order < 16)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old;
-			else
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
-		}
-		else
-			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
-
-		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;
-		}
-		else {
-			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
-			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
-		}
-
-		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 */
-#   if FLAC__HAS_X86INTRIN
-#    if defined FLAC__SSE_SUPPORTED
-		if(encoder->private_->cpuinfo.ia32.sse) {
-			if(encoder->private_->cpuinfo.ia32.sse42 || !encoder->private_->cpuinfo.ia32.intel) { /* use new autocorrelation functions */
-				if(encoder->protected_->max_lpc_order < 4)
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new;
-				else if(encoder->protected_->max_lpc_order < 8)
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new;
-				else if(encoder->protected_->max_lpc_order < 12)
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new;
-				else if(encoder->protected_->max_lpc_order < 16)
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new;
-				else
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
-			}
-			else { /* use old autocorrelation functions */
-				if(encoder->protected_->max_lpc_order < 4)
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old;
-				else if(encoder->protected_->max_lpc_order < 8)
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old;
-				else if(encoder->protected_->max_lpc_order < 12)
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old;
-				else if(encoder->protected_->max_lpc_order < 16)
-					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old;
-				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);
-#   if FLAC__HAS_X86INTRIN
-#    ifdef FLAC__SSE_SUPPORTED
-		if(encoder->private_->cpuinfo.x86.sse42 || !encoder->private_->cpuinfo.x86.intel) { /* use new autocorrelation functions */
-			if(encoder->protected_->max_lpc_order < 4)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new;
-			else if(encoder->protected_->max_lpc_order < 8)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new;
-			else if(encoder->protected_->max_lpc_order < 12)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new;
-			else if(encoder->protected_->max_lpc_order < 16)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new;
-		}
-		else {
-			if(encoder->protected_->max_lpc_order < 4)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old;
-			else if(encoder->protected_->max_lpc_order < 8)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old;
-			else if(encoder->protected_->max_lpc_order < 12)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old;
-			else if(encoder->protected_->max_lpc_order < 16)
-				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old;
-		}
-#    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 /* !FLAC__NO_ASM */
-#endif /* !FLAC__INTEGER_ONLY_LIBRARY */
-#if !defined FLAC__NO_ASM && 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 */
-
-	/* 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 FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_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
-	 */
-	if(encoder->protected_->verify) {
-		/*
-		 * First, set up the fifo which will hold the
-		 * original signal to compare against
-		 */
-		encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_;
-		for(i = 0; i < encoder->protected_->channels; i++) {
-			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;
-
-		/*
-		 * Now set up a stream decoder for verification
-		 */
-		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;
-			}
-		}
-
-		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;
-	encoder->private_->verify.error_stats.channel = 0;
-	encoder->private_->verify.error_stats.sample = 0;
-	encoder->private_->verify.error_stats.expected = 0;
-	encoder->private_->verify.error_stats.got = 0;
-
-	/*
-	 * 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__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 FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
-	}
-
-	/*
-	 * write the STREAMINFO metadata block
-	 */
-	if(encoder->protected_->verify)
-		encoder->private_->verify.state_hint = ENCODER_IN_METADATA;
-	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 FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
-	}
-
-	/*
-	 * Now that the STREAMINFO block is written, we can init this to an
-	 * absurdly-high value...
-	 */
-	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_->streaminfo.data.stream_info.total_samples = 0;
-
-	/*
-	 * Check to see if the supplied metadata contains a VORBIS_COMMENT;
-	 * if not, we will write an empty one (FLAC__add_metadata_block()
-	 * automatically supplies the vendor string).
-	 *
-	 * WATCHOUT: 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;
-		vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
-		vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0);
-		vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */
-		vorbis_comment.data.vorbis_comment.vendor_string.length = 0;
-		vorbis_comment.data.vorbis_comment.vendor_string.entry = 0;
-		vorbis_comment.data.vorbis_comment.num_comments = 0;
-		vorbis_comment.data.vorbis_comment.comments = 0;
-		if(!FLAC__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 FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
-		}
-	}
-
-	/*
-	 * write the user's metadata blocks
-	 */
-	for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
-		encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1);
-		if(!FLAC__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 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 FLAC__STREAM_ENCODER_INIT_STATUS_OK;
-}
-
-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.
-	 */
-	if(GetFileType((HANDLE)_get_osfhandle(_fileno(file))) == FILE_TYPE_DISK)
-		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 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;
-			if(!process_frame_(encoder, is_fractional_block, /*is_last_block=*/true))
-				error = true;
-		}
-	}
-
-	if(encoder->protected_->do_md5)
-		FLAC__MD5Final(encoder->private_->streaminfo.data.stream_info.md5sum, &encoder->private_->md5context);
-
-	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(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);
-
-	if(!error)
-		encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
-
-	return !error;
-}
-
-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;
-#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_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;
-#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
-	encoder->protected_->verify = value;
-#endif
-	return true;
-}
-
-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_->streamable_subset = value;
-	return true;
-}
-
-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_->do_md5 = value;
-	return true;
-}
-
-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;
-	return true;
-}
-
-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;
-	return true;
-}
-
-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;
-	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;
-	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;
-	return true;
-}
-
-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;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
-{
-	FLAC__ASSERT(0 != encoder);
-	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;
-	return true;
-}
-
-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
-	/*@@@ deprecated: */
-	encoder->protected_->do_escape_coding = value;
-#else
-	(void)value;
-#endif
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
-{
-	FLAC__ASSERT(0 != encoder);
-	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;
-	return true;
-}
-
-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;
-	return true;
-}
-
-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;
-	return true;
-}
-
-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
-	/*@@@ deprecated: */
-	encoder->protected_->rice_parameter_search_dist = value;
-#else
-	(void)value;
-#endif
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value)
-{
-	FLAC__ASSERT(0 != encoder);
-	FLAC__ASSERT(0 != encoder->private_);
-	FLAC__ASSERT(0 != encoder->protected_);
-	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
-		return false;
-	value = flac_min(value, (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN) - 1);
-	encoder->protected_->total_samples_estimate = value;
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
-{
-	FLAC__ASSERT(0 != encoder);
-	FLAC__ASSERT(0 != encoder->private_);
-	FLAC__ASSERT(0 != encoder->protected_);
-	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
-		return false;
-	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;
-#endif
-	return true;
-}
-
-/*
- * These three functions are not static, but not publically exposed in
- * include/FLAC/ either.  They are used by the test suite.
- */
-FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
-{
-	FLAC__ASSERT(0 != encoder);
-	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;
-	return true;
-}
-
-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;
-	return true;
-}
-
-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;
-	return true;
-}
-
-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;
-}
-
-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
-		return FLAC__STREAM_DECODER_UNINITIALIZED;
-}
-
-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
-		return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder);
-}
-
-FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
-{
-	FLAC__ASSERT(0 != encoder);
-	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)
-		*frame_number = encoder->private_->verify.error_stats.frame_number;
-	if(0 != channel)
-		*channel = encoder->private_->verify.error_stats.channel;
-	if(0 != sample)
-		*sample = encoder->private_->verify.error_stats.sample;
-	if(0 != expected)
-		*expected = encoder->private_->verify.error_stats.expected;
-	if(0 != got)
-		*got = encoder->private_->verify.error_stats.got;
-}
-
-FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder)
-{
-	FLAC__ASSERT(0 != encoder);
-	FLAC__ASSERT(0 != encoder->private_);
-	FLAC__ASSERT(0 != encoder->protected_);
-	return encoder->protected_->verify;
-}
-
-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_md5(const FLAC__StreamEncoder *encoder)
-{
-	FLAC__ASSERT(0 != encoder);
-	FLAC__ASSERT(0 != encoder->private_);
-	FLAC__ASSERT(0 != encoder->protected_);
-	return encoder->protected_->do_md5;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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 = 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);
-
-	do {
-		const unsigned n = flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j);
-
-		if(encoder->protected_->verify)
-			append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n);
-
-		for(channel = 0; channel < channels; channel++) {
-			if (buffer[channel] == NULL) {
-				return false;
-			}
-			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' ! */
-			}
-		}
-		else
-			j += n;
-
-		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];
-			}
-			encoder->private_->current_sample_number = 1;
-		}
-	} while(j < samples);
-
-	return true;
-}
-
-FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
-{
-	unsigned i, j, k, channel;
-	FLAC__int32 x, mid, side;
-	const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
-
-	FLAC__ASSERT(0 != encoder);
-	FLAC__ASSERT(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, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j));
-
-			/* "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;
-				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_->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, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j));
-
-			/* "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++];
-			}
-			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);
-	}
-
-	return true;
-}
-
-/***********************************************************************
- *
- * Private class methods
- *
- ***********************************************************************/
-
-void set_defaults_(FLAC__StreamEncoder *encoder)
-{
-	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 = 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;
-	encoder->protected_->do_exhaustive_model_search = false;
-	encoder->protected_->do_escape_coding = false;
-	encoder->protected_->min_residual_partition_order = 0;
-	encoder->protected_->max_residual_partition_order = 0;
-	encoder->protected_->rice_parameter_search_dist = 0;
-	encoder->protected_->total_samples_estimate = 0;
-	encoder->protected_->metadata = 0;
-	encoder->protected_->num_metadata_blocks = 0;
-
-	encoder->private_->seek_table = 0;
-	encoder->private_->disable_constant_subframes = false;
-	encoder->private_->disable_fixed_subframes = false;
-	encoder->private_->disable_verbatim_subframes = false;
-	encoder->private_->is_ogg = false;
-	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)
-{
-	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]) {
-			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]) {
-				free(encoder->private_->residual_workspace_unaligned[channel][i]);
-				encoder->private_->residual_workspace_unaligned[channel][i] = 0;
-			}
-		}
-	}
-	for(channel = 0; channel < 2; channel++) {
-		for(i = 0; i < 2; i++) {
-			if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) {
-				free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]);
-				encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0;
-			}
-		}
-	}
-	if(0 != encoder->private_->abs_residual_partition_sums_unaligned) {
-		free(encoder->private_->abs_residual_partition_sums_unaligned);
-		encoder->private_->abs_residual_partition_sums_unaligned = 0;
-	}
-	if(0 != encoder->private_->raw_bits_per_partition_unaligned) {
-		free(encoder->private_->raw_bits_per_partition_unaligned);
-		encoder->private_->raw_bits_per_partition_unaligned = 0;
-	}
-	if(encoder->protected_->verify) {
-		for(i = 0; i < encoder->protected_->channels; i++) {
-			if(0 != encoder->private_->verify.input_fifo.data[i]) {
-				free(encoder->private_->verify.input_fifo.data[i]);
-				encoder->private_->verify.input_fifo.data[i] = 0;
-			}
-		}
-	}
-	FLAC__bitwriter_free(encoder->private_->frame);
-}
-
-FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize)
-{
-	FLAC__bool ok;
-	unsigned i, channel;
-
-	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_blocksize <= encoder->private_->input_capacity)
-		return true;
-
-	ok = true;
-
-	/* 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 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_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_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_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_blocksize, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]);
-		}
-	}
-	/* 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_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_blocksize;
-	else
-		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
-
-	return ok;
-}
-
-FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block)
-{
-	const FLAC__byte *buffer;
-	size_t bytes;
-
-	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame));
-
-	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;
-		encoder->private_->verify.output.bytes = bytes;
-		if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) {
-			encoder->private_->verify.needs_magic_hack = true;
-		}
-		else {
-			if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)
-			    || (!is_last_block
-				    && (FLAC__stream_encoder_get_verify_decoder_state(encoder) == FLAC__STREAM_DECODER_END_OF_STREAM))) {
-				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;
-			}
-		}
-	}
-
-	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__bitwriter_release_buffer(encoder->private_->frame);
-	FLAC__bitwriter_clear(encoder->private_->frame);
-
-	if(samples > 0) {
-		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__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(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;
-	}
-
-	/*
-	 * Process the frame header and subframes into the frame bitbuffer
-	 */
-	if(!process_subframes_(encoder, is_fractional_block)) {
-		/* the above function sets the state for us in case of an error */
-		return false;
-	}
-
-	/*
-	 * Zero-pad the frame to a byte_boundary
-	 */
-	if(!FLAC__bitwriter_zero_pad_to_byte_boundary(encoder->private_->frame)) {
-		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
-		return false;
-	}
-
-	/*
-	 * CRC-16 the whole thing
-	 */
-	FLAC__ASSERT(FLAC__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, is_last_block)) {
-		/* the above function sets the state for us in case of an error */
-		return false;
-	}
-
-	/*
-	 * Get ready for the next frame
-	 */
-	encoder->private_->current_sample_number = 0;
-	encoder->private_->current_frame_number++;
-	encoder->private_->streaminfo.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize;
-
-	return true;
-}
-
-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;
-
-	/*
-	 * Calculate the min,max Rice partition orders
-	 */
-	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 = flac_min(max_partition_order, encoder->protected_->max_residual_partition_order);
-	}
-	min_partition_order = flac_min(min_partition_order, max_partition_order);
-
-	/*
-	 * Setup the frame
-	 */
-	frame_header.blocksize = encoder->protected_->blocksize;
-	frame_header.sample_rate = encoder->protected_->sample_rate;
-	frame_header.channels = encoder->protected_->channels;
-	frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */
-	frame_header.bits_per_sample = encoder->protected_->bits_per_sample;
-	frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
-	frame_header.number.frame_number = encoder->private_->current_frame_number;
-
-	/*
-	 * Figure out what channel assignments to try
-	 */
-	if(encoder->protected_->do_mid_side_stereo) {
-		if(encoder->protected_->loose_mid_side_stereo) {
-			if(encoder->private_->loose_mid_side_stereo_frame_count == 0) {
-				do_independent = true;
-				do_mid_side = true;
-			}
-			else {
-				do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT);
-				do_mid_side = !do_independent;
-			}
-		}
-		else {
-			do_independent = true;
-			do_mid_side = true;
-		}
-	}
-	else {
-		do_independent = true;
-		do_mid_side = false;
-	}
-
-	FLAC__ASSERT(do_independent || do_mid_side);
-
-	/*
-	 * Check for wasted bits; set effective bps for each subframe
-	 */
-	if(do_independent) {
-		for(channel = 0; channel < encoder->protected_->channels; channel++) {
-			unsigned w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
-			if (w > encoder->protected_->bits_per_sample) {
-				w = encoder->protected_->bits_per_sample;
-			}
-			encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w;
-			encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w;
-		}
-	}
-	if(do_mid_side) {
-		FLAC__ASSERT(encoder->protected_->channels == 2);
-		for(channel = 0; channel < 2; channel++) {
-			unsigned w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
-			if (w > encoder->protected_->bits_per_sample) {
-				w = encoder->protected_->bits_per_sample;
-			}
-			encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w;
-			encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1);
-		}
-	}
-
-	/*
-	 * First do a normal encoding pass of each independent channel
-	 */
-	if(do_independent) {
-		for(channel = 0; channel < encoder->protected_->channels; channel++) {
-			if(!
-				process_subframe_(
-					encoder,
-					min_partition_order,
-					max_partition_order,
-					&frame_header,
-					encoder->private_->subframe_bps[channel],
-					encoder->private_->integer_signal[channel],
-					encoder->private_->subframe_workspace_ptr[channel],
-					encoder->private_->partitioned_rice_contents_workspace_ptr[channel],
-					encoder->private_->residual_workspace[channel],
-					encoder->private_->best_subframe+channel,
-					encoder->private_->best_subframe_bits+channel
-				)
-			)
-				return false;
-		}
-	}
-
-	/*
-	 * Now do mid and side channels if requested
-	 */
-	if(do_mid_side) {
-		FLAC__ASSERT(encoder->protected_->channels == 2);
-
-		for(channel = 0; channel < 2; channel++) {
-			if(!
-				process_subframe_(
-					encoder,
-					min_partition_order,
-					max_partition_order,
-					&frame_header,
-					encoder->private_->subframe_bps_mid_side[channel],
-					encoder->private_->integer_signal_mid_side[channel],
-					encoder->private_->subframe_workspace_ptr_mid_side[channel],
-					encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel],
-					encoder->private_->residual_workspace_mid_side[channel],
-					encoder->private_->best_subframe_mid_side+channel,
-					encoder->private_->best_subframe_bits_mid_side+channel
-				)
-			)
-				return false;
-		}
-	}
-
-	/*
-	 * Compose the frame bitbuffer
-	 */
-	if(do_mid_side) {
-		unsigned left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */
-		FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */
-		FLAC__ChannelAssignment channel_assignment;
-
-		FLAC__ASSERT(encoder->protected_->channels == 2);
-
-		if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) {
-			channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE);
-		}
-		else {
-			unsigned bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
-			unsigned min_bits;
-			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 */
-			bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits         [0] + encoder->private_->best_subframe_bits         [1];
-			bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE  ] = encoder->private_->best_subframe_bits         [0] + encoder->private_->best_subframe_bits_mid_side[1];
-			bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits         [1] + encoder->private_->best_subframe_bits_mid_side[1];
-			bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE   ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1];
-
-			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 = (FLAC__ChannelAssignment)ca;
-				}
-			}
-		}
-
-		frame_header.channel_assignment = channel_assignment;
-
-		if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
-			encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
-			return false;
-		}
-
-		switch(channel_assignment) {
-			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
-				left_subframe  = &encoder->private_->subframe_workspace         [0][encoder->private_->best_subframe         [0]];
-				right_subframe = &encoder->private_->subframe_workspace         [1][encoder->private_->best_subframe         [1]];
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
-				left_subframe  = &encoder->private_->subframe_workspace         [0][encoder->private_->best_subframe         [0]];
-				right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
-				left_subframe  = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
-				right_subframe = &encoder->private_->subframe_workspace         [1][encoder->private_->best_subframe         [1]];
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
-				left_subframe  = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]];
-				right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
-				break;
-			default:
-				FLAC__ASSERT(0);
-		}
-
-		switch(channel_assignment) {
-			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
-				left_bps  = encoder->private_->subframe_bps         [0];
-				right_bps = encoder->private_->subframe_bps         [1];
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
-				left_bps  = encoder->private_->subframe_bps         [0];
-				right_bps = encoder->private_->subframe_bps_mid_side[1];
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
-				left_bps  = encoder->private_->subframe_bps_mid_side[1];
-				right_bps = encoder->private_->subframe_bps         [1];
-				break;
-			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
-				left_bps  = encoder->private_->subframe_bps_mid_side[0];
-				right_bps = encoder->private_->subframe_bps_mid_side[1];
-				break;
-			default:
-				FLAC__ASSERT(0);
-		}
-
-		/* note that encoder_add_subframe_ sets the state for us in case of an error */
-		if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame))
-			return false;
-		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->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.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;
-			}
-		}
-	}
-
-	if(encoder->protected_->loose_mid_side_stereo) {
-		encoder->private_->loose_mid_side_stereo_frame_count++;
-		if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames)
-			encoder->private_->loose_mid_side_stereo_frame_count = 0;
-	}
-
-	encoder->private_->last_channel_assignment = frame_header.channel_assignment;
-
-	return true;
-}
-
-FLAC__bool process_subframe_(
-	FLAC__StreamEncoder *encoder,
-	unsigned min_partition_order,
-	unsigned max_partition_order,
-	const FLAC__FrameHeader *frame_header,
-	unsigned subframe_bps,
-	const FLAC__int32 integer_signal[],
-	FLAC__Subframe *subframe[2],
-	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
-	FLAC__int32 *residual[2],
-	unsigned *best_subframe,
-	unsigned *best_bits
-)
-{
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-	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
-	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 */
-	double lpc_error[FLAC__MAX_LPC_ORDER];
-	unsigned min_lpc_order, max_lpc_order, lpc_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_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
-
-	if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) {
-		unsigned signal_is_constant = false;
-		if(subframe_bps + 4 + FLAC__bitmath_ilog2((frame_header->blocksize-FLAC__MAX_FIXED_ORDER)|1) <= 32)
-			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);
-		else
-			guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor_wide(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 &&
-#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 < frame_header->blocksize; i++) {
-				if(integer_signal[0] != integer_signal[i]) {
-					signal_is_constant = false;
-					break;
-				}
-			}
-		}
-		if(signal_is_constant) {
-			_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;
-			}
-		}
-		else {
-			if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) {
-				/* encode fixed */
-				if(encoder->protected_->do_exhaustive_model_search) {
-					min_fixed_order = 0;
-					max_fixed_order = FLAC__MAX_FIXED_ORDER;
-				}
-				else {
-					min_fixed_order = max_fixed_order = guess_fixed_order;
-				}
-				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++) {
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-					if(fixed_residual_bits_per_sample[fixed_order] >= (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 */
-#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
-					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, rice_parameter_limit - 1);
-#endif
-						rice_parameter = rice_parameter_limit - 1;
-					}
-					_candidate_bits =
-						evaluate_fixed_subframe_(
-							encoder,
-							integer_signal,
-							residual[!_best_subframe],
-							encoder->private_->abs_residual_partition_sums,
-							encoder->private_->raw_bits_per_partition,
-							frame_header->blocksize,
-							subframe_bps,
-							fixed_order,
-							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 < _best_bits) {
-						_best_subframe = !_best_subframe;
-						_best_bits = _candidate_bits;
-					}
-				}
-			}
-
-#ifndef FLAC__INTEGER_ONLY_LIBRARY
-			/* encode lpc */
-			if(encoder->protected_->max_lpc_order > 0) {
-				if(encoder->protected_->max_lpc_order >= frame_header->blocksize)
-					max_lpc_order = frame_header->blocksize-1;
-				else
-					max_lpc_order = encoder->protected_->max_lpc_order;
-				if(max_lpc_order > 0) {
-					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;
-							}
-							else {
-								const unsigned guess_lpc_order =
-									FLAC__lpc_compute_best_order(
-										lpc_error,
-										max_lpc_order,
-										frame_header->blocksize,
-										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
-										)
-									);
-								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 >= (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(+1bps for side channel) streams */
-									if(subframe_bps <= 17) {
-										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 */
-		}
-	}
-
-	/* 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_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
-	}
-
-	*best_subframe = _best_subframe;
-	*best_bits = _best_bits;
-
-	return true;
-}
-
-FLAC__bool add_subframe_(
-	FLAC__StreamEncoder *encoder,
-	unsigned blocksize,
-	unsigned subframe_bps,
-	const FLAC__Subframe *subframe,
-	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_FRAMING_ERROR;
-				return false;
-			}
-			break;
-		case FLAC__SUBFRAME_TYPE_FIXED:
-			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), 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), blocksize, subframe_bps, subframe->wasted_bits, frame)) {
-				encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
-				return false;
-			}
-			break;
-		default:
-			FLAC__ASSERT(0);
-	}
-
-	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;
-
-	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_(
-	FLAC__StreamEncoder *encoder,
-	const FLAC__int32 signal[],
-	FLAC__int32 residual[],
-	FLAC__uint64 abs_residual_partition_sums[],
-	unsigned raw_bits_per_partition[],
-	unsigned blocksize,
-	unsigned subframe_bps,
-	unsigned order,
-	unsigned rice_parameter,
-	unsigned rice_parameter_limit,
-	unsigned min_partition_order,
-	unsigned max_partition_order,
-	FLAC__bool do_escape_coding,
-	unsigned rice_parameter_search_dist,
-	FLAC__Subframe *subframe,
-	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
-)
-{
-	unsigned i, residual_bits, estimate;
-	const unsigned residual_samples = blocksize - order;
-
-	FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual);
-
-	subframe->type = FLAC__SUBFRAME_TYPE_FIXED;
-
-	subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
-	subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
-	subframe->data.fixed.residual = residual;
-
-	residual_bits =
-		find_best_partition_order_(
-			encoder->private_,
-			residual,
-			abs_residual_partition_sums,
-			raw_bits_per_partition,
-			residual_samples,
-			order,
-			rice_parameter,
-			rice_parameter_limit,
-			min_partition_order,
-			max_partition_order,
-			subframe_bps,
-			do_escape_coding,
-			rice_parameter_search_dist,
-			&subframe->data.fixed.entropy_coding_method
-		);
-
-	subframe->data.fixed.order = order;
-	for(i = 0; i < order; i++)
-		subframe->data.fixed.warmup[i] = signal[i];
-
-	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__uint64 abs_residual_partition_sums[],
-	unsigned raw_bits_per_partition[],
-	const FLAC__real lp_coeff[],
-	unsigned blocksize,
-	unsigned subframe_bps,
-	unsigned order,
-	unsigned qlp_coeff_precision,
-	unsigned rice_parameter,
-	unsigned rice_parameter_limit,
-	unsigned min_partition_order,
-	unsigned max_partition_order,
-	FLAC__bool do_escape_coding,
-	unsigned rice_parameter_search_dist,
-	FLAC__Subframe *subframe,
-	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
-)
-{
-	FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; /* 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;
-
-	/* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps(+1bps for side channel) streams */
-	if(subframe_bps <= 17) {
-		FLAC__ASSERT(order > 0);
-		FLAC__ASSERT(order <= FLAC__MAX_LPC_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);
-	if(ret != 0)
-		return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */
-
-	if(subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
-		if(subframe_bps <= 16 && qlp_coeff_precision <= 16)
-			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
-		else
-			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
-	else
-		encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
-
-	subframe->type = FLAC__SUBFRAME_TYPE_LPC;
-
-	subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
-	subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
-	subframe->data.lpc.residual = residual;
-
-	residual_bits =
-		find_best_partition_order_(
-			encoder->private_,
-			residual,
-			abs_residual_partition_sums,
-			raw_bits_per_partition,
-			residual_samples,
-			order,
-			rice_parameter,
-			rice_parameter_limit,
-			min_partition_order,
-			max_partition_order,
-			subframe_bps,
-			do_escape_coding,
-			rice_parameter_search_dist,
-			&subframe->data.lpc.entropy_coding_method
-		);
-
-	subframe->data.lpc.order = order;
-	subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision;
-	subframe->data.lpc.quantization_level = quantization;
-	memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(FLAC__int32)*FLAC__MAX_LPC_ORDER);
-	for(i = 0; i < order; i++)
-		subframe->data.lpc.warmup[i] = signal[i];
-
-	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,
-	FLAC__Subframe *subframe
-)
-{
-	unsigned estimate;
-
-	subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM;
-
-	subframe->data.verbatim.data = signal;
-
-	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__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,
-	unsigned bps,
-	FLAC__bool do_escape_coding,
-	unsigned rice_parameter_search_dist,
-	FLAC__EntropyCodingMethod *best_ecm
-)
-{
-	unsigned residual_bits, best_residual_bits = 0;
-	unsigned best_parameters_index = 0;
-	unsigned best_partition_order = 0;
-	const unsigned blocksize = residual_samples + predictor_order;
-
-	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 = flac_min(min_partition_order, max_partition_order);
-
-	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;
-
-		for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) {
-			if(!
-				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,
-					&private_->partitioned_rice_contents_extra[!best_parameters_index],
-					&residual_bits
-				)
-			)
-			{
-				FLAC__ASSERT(best_residual_bits != 0);
-				break;
-			}
-			sum += 1u << partition_order;
-			if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
-				best_residual_bits = residual_bits;
-				best_parameters_index = !best_parameters_index;
-				best_partition_order = partition_order;
-			}
-		}
-	}
-
-	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;
-			}
-		}
-	}
-
-	return best_residual_bits;
-}
-
-void 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
-)
-{
-	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 */
-	{
-		const unsigned threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
-		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(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
-			for(partition = residual_sample = 0; partition < partitions; partition++) {
-				FLAC__uint32 abs_residual_partition_sum = 0;
-				end += default_partition_samples;
-				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 */
-			for(partition = residual_sample = 0; partition < partitions; partition++) {
-				FLAC__uint64 abs_residual_partition_sum64 = 0;
-				end += default_partition_samples;
-				for( ; residual_sample < end; residual_sample++)
-					abs_residual_partition_sum64 += 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_sum64;
-			}
-		}
-	}
-
-	/* now merge partitions for lower orders */
-	{
-		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;
-			}
-		}
-	}
-}
-
-void precompute_partition_info_escapes_(
-	const FLAC__int32 residual[],
-	unsigned raw_bits_per_partition[],
-	unsigned residual_samples,
-	unsigned predictor_order,
-	unsigned min_partition_order,
-	unsigned max_partition_order
-)
-{
-	int partition_order;
-	unsigned from_partition, to_partition = 0;
-	const unsigned blocksize = residual_samples + predictor_order;
-
-	/* first do max_partition_order */
-	for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) {
-		FLAC__int32 r;
-		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;
-
-		FLAC__ASSERT(default_partition_samples > predictor_order);
-
-		for(partition = residual_sample = 0; partition < partitions; partition++) {
-			partition_samples = default_partition_samples;
-			if(partition == 0)
-				partition_samples -= predictor_order;
-			rmax = 0;
-			for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) {
-				r = residual[residual_sample++];
-				/* OPT: maybe faster: rmax |= r ^ (r>>31) */
-				if(r < 0)
-					rmax |= ~r;
-				else
-					rmax |= r;
-			}
-			/* 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; /*@@@ yuck, should remove the 'for' loop instead */
-	}
-
-	/* now merge partitions for lower orders */
-	for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) {
-		unsigned m;
-		unsigned i;
-		const unsigned partitions = 1u << partition_order;
-		for(i = 0; i < partitions; i++) {
-			m = raw_bits_per_partition[from_partition];
-			from_partition++;
-			raw_bits_per_partition[to_partition] = flac_max(m, raw_bits_per_partition[from_partition]);
-			from_partition++;
-			to_partition++;
-		}
-	}
-}
-
-#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
-static inline unsigned count_rice_bits_in_partition_(
-	const unsigned rice_parameter,
-	const unsigned partition_samples,
-	const FLAC__uint64 abs_residual_partition_sum
-)
-{
-	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
-
-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,
-	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
-	unsigned *bits
-)
-{
-	unsigned rice_parameter, partition_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_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, flac_max(6u, partition_order));
-	parameters = partitioned_rice_contents->parameters;
-	raw_bits = partitioned_rice_contents->raw_bits;
-
-	if(partition_order == 0) {
-		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;
-			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 >= rice_parameter_limit) {
-#ifdef DEBUG_VERBOSE
-				fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, rice_parameter_limit - 1);
-#endif
-				max_rice_parameter = rice_parameter_limit - 1;
-			}
-		}
-		else
-			min_rice_parameter = max_rice_parameter = suggested_rice_parameter;
-
-		for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
-#else
-			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 = count_rice_bits_in_partition_(rice_parameter, residual_samples, abs_residual_partition_sums[0]);
-#endif
-			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) {
-			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 = 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;
-		unsigned partition_samples;
-		FLAC__uint64 mean, k;
-		const unsigned partitions = 1u << partition_order;
-		for(partition = residual_sample = 0; partition < partitions; partition++) {
-			partition_samples = (residual_samples+predictor_order) >> partition_order;
-			if(partition == 0) {
-				if(partition_samples <= predictor_order)
-					return false;
-				else
-					partition_samples -= predictor_order;
-			}
-			mean = abs_residual_partition_sums[partition];
-			/* 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
-				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, rice_parameter_limit - 1);
-#endif
-				rice_parameter = rice_parameter_limit - 1;
-			}
-
-			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;
-				else
-					min_rice_parameter = rice_parameter - rice_parameter_search_dist;
-				max_rice_parameter = rice_parameter + rice_parameter_search_dist;
-				if(max_rice_parameter >= rice_parameter_limit) {
-#ifdef DEBUG_VERBOSE
-					fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, rice_parameter_limit - 1);
-#endif
-					max_rice_parameter = rice_parameter_limit - 1;
-				}
-			}
-			else
-				min_rice_parameter = max_rice_parameter = rice_parameter;
-
-			for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
-#endif
-#ifdef EXACT_RICE_BITS_CALCULATION
-				partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, residual+residual_sample);
-#else
-				partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, abs_residual_partition_sums[partition]);
-#endif
-				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) {
-				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 = 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;
-		}
-	}
-
-	*bits = bits_;
-	return true;
-}
-
-unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples)
-{
-	unsigned i, shift;
-	FLAC__int32 x = 0;
-
-	for(i = 0; i < samples && !(x&1); i++)
-		x |= signal[i];
-
-	if(x == 0) {
-		shift = 0;
-	}
-	else {
-		for(shift = 0; !(x&1); shift++)
-			x >>= 1;
-	}
-
-	if(shift > 0) {
-		for(i = 0; i < samples; i++)
-			 signal[i] >>= shift;
-	}
-
-	return shift;
-}
-
-void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
-{
-	unsigned channel;
-
-	for(channel = 0; channel < channels; channel++)
-		memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples);
-
-	fifo->tail += wide_samples;
-
-	FLAC__ASSERT(fifo->tail <= fifo->size);
-}
-
-void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
-{
-	unsigned channel;
-	unsigned sample, wide_sample;
-	unsigned tail = fifo->tail;
-
-	sample = input_offset * channels;
-	for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
-		for(channel = 0; channel < channels; channel++)
-			fifo->data[channel][tail] = input[sample++];
-		tail++;
-	}
-	fifo->tail = tail;
-
-	FLAC__ASSERT(fifo->tail <= fifo->size);
-}
-
-FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
-{
-	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
-	const size_t encoded_bytes = encoder->private_->verify.output.bytes;
-	(void)decoder;
-
-	if(encoder->private_->verify.needs_magic_hack) {
-		FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH);
-		*bytes = FLAC__STREAM_SYNC_LENGTH;
-		memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes);
-		encoder->private_->verify.needs_magic_hack = false;
-	}
-	else {
-		if(encoded_bytes == 0) {
-			/*
-			 * If we get here, a FIFO underflow has occurred,
-			 * which means there is a bug somewhere.
-			 */
-			FLAC__ASSERT(0);
-			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
-		}
-		else if(encoded_bytes < *bytes)
-			*bytes = encoded_bytes;
-		memcpy(buffer, encoder->private_->verify.output.data, *bytes);
-		encoder->private_->verify.output.data += *bytes;
-		encoder->private_->verify.output.bytes -= *bytes;
-	}
-
-	return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
-}
-
-FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
-{
-	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data;
-	unsigned channel;
-	const unsigned channels = 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;
-			FLAC__int32 expect = 0, got = 0;
-
-			for(i = 0; i < blocksize; i++) {
-				if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) {
-					sample = i;
-					expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i];
-					got = (FLAC__int32)buffer[channel][i];
-					break;
-				}
-			}
-			FLAC__ASSERT(i < blocksize);
-			FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
-			encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample;
-			encoder->private_->verify.error_stats.frame_number = (unsigned)(frame->header.number.sample_number / blocksize);
-			encoder->private_->verify.error_stats.channel = channel;
-			encoder->private_->verify.error_stats.sample = sample;
-			encoder->private_->verify.error_stats.expected = expect;
-			encoder->private_->verify.error_stats.got = got;
-			encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
-			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
-		}
-	}
-	/* dequeue the frame from the fifo */
-	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;
-}
-
-void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
-{
-	(void)decoder, (void)metadata, (void)client_data;
-}
-
-void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
-{
-	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
-	(void)decoder, (void)status;
-	encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
-}
-
-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;
-}
diff --git a/libFLAC/stream_encoder_framing.c b/libFLAC/stream_encoder_framing.c
deleted file mode 100644
index 0929cd7..0000000
--- a/libFLAC/stream_encoder_framing.c
+++ /dev/null
@@ -1,554 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 <stdio.h>
-#include <string.h> /* for strlen() */
-#include "private/stream_encoder_framing.h"
-#include "private/crc.h"
-#include "FLAC/assert.h"
-#include "share/compat.h"
-
-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);
-
-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__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN))
-		return false;
-
-	if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN))
-		return false;
-
-	/*
-	 * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string
-	 */
-	i = metadata->length;
-	if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
-		FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry);
-		i -= metadata->data.vorbis_comment.vendor_string.length;
-		i += vendor_string_length;
-	}
-	FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
-	/* double protection */
-	if(i >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
-		return false;
-	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__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__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__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__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__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__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__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
-				return false;
-			FLAC__ASSERT(metadata->data.stream_info.total_samples < (FLAC__U64L(1) << 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__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16))
-				return false;
-			break;
-		case FLAC__METADATA_TYPE_PADDING:
-			if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8))
-				return false;
-			break;
-		case FLAC__METADATA_TYPE_APPLICATION:
-			if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))
-				return false;
-			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__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
-					return false;
-				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__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__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length))
-				return false;
-			if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length))
-				return false;
-			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__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length))
-					return false;
-				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__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__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
-				return false;
-			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__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
-				return false;
-			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__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
-					return false;
-				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__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
-					return false;
-				if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
-					return false;
-				if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
-					return false;
-				if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
-					return false;
-				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 *indx = track->indices + j;
-
-					if(!FLAC__bitwriter_write_raw_uint64(bw, indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
-						return false;
-					if(!FLAC__bitwriter_write_raw_uint32(bw, indx->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
-						return false;
-					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__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length))
-				return false;
-			break;
-	}
-
-	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
-	return true;
-}
-
-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__bitwriter_is_byte_aligned(bw));
-
-	if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
-		return false;
-
-	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);
-	blocksize_hint = 0;
-	switch(header->blocksize) {
-		case   192: u = 1; break;
-		case   576: u = 2; break;
-		case  1152: u = 3; break;
-		case  2304: u = 4; break;
-		case  4608: u = 5; break;
-		case   256: u = 8; break;
-		case   512: u = 9; break;
-		case  1024: u = 10; break;
-		case  2048: u = 11; break;
-		case  4096: u = 12; break;
-		case  8192: u = 13; break;
-		case 16384: u = 14; break;
-		case 32768: u = 15; break;
-		default:
-			if(header->blocksize <= 0x100)
-				blocksize_hint = u = 6;
-			else
-				blocksize_hint = u = 7;
-			break;
-	}
-	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  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;
-			else if(header->sample_rate % 10 == 0)
-				sample_rate_hint = u = 14;
-			else if(header->sample_rate <= 0xffff)
-				sample_rate_hint = u = 13;
-			else
-				u = 0;
-			break;
-	}
-	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);
-	switch(header->channel_assignment) {
-		case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
-			u = header->channels - 1;
-			break;
-		case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
-			FLAC__ASSERT(header->channels == 2);
-			u = 8;
-			break;
-		case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
-			FLAC__ASSERT(header->channels == 2);
-			u = 9;
-			break;
-		case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
-			FLAC__ASSERT(header->channels == 2);
-			u = 10;
-			break;
-		default:
-			FLAC__ASSERT(0);
-	}
-	if(!FLAC__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));
-	switch(header->bits_per_sample) {
-		case 8 : u = 1; break;
-		case 12: u = 2; break;
-		case 16: u = 4; break;
-		case 20: u = 5; break;
-		case 24: u = 6; break;
-		default: u = 0; break;
-	}
-	if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN))
-		return false;
-
-	if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN))
-		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__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16))
-			return false;
-
-	switch(sample_rate_hint) {
-		case 12:
-			if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8))
-				return false;
-			break;
-		case 13:
-			if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16))
-				return false;
-			break;
-		case 14:
-			if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16))
-				return false;
-			break;
-	}
-
-	/* write the CRC */
-	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__BitWriter *bw)
-{
-	FLAC__bool ok;
-
-	ok =
-		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__BitWriter *bw)
-{
-	unsigned i;
-
-	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__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
-			return false;
-
-	for(i = 0; i < subframe->order; i++)
-		if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
-			return false;
-
-	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:
-		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:
-			FLAC__ASSERT(0);
-	}
-
-	return true;
-}
-
-FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
-{
-	unsigned i;
-
-	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__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
-			return false;
-
-	for(i = 0; i < subframe->order; i++)
-		if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
-			return false;
-
-	if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
-		return false;
-	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__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision))
-			return false;
-
-	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:
-		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:
-			FLAC__ASSERT(0);
-	}
-
-	return true;
-}
-
-FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
-{
-	unsigned i;
-	const FLAC__int32 *signal = subframe->data;
-
-	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__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
-			return false;
-
-	for(i = 0; i < samples; i++)
-		if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps))
-			return false;
-
-	return true;
-}
-
-FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method)
-{
-	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:
-		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:
-			FLAC__ASSERT(0);
-	}
-	return true;
-}
-
-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(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 {
-			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__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0]))
-					return false;
-			}
-		}
-		return true;
-	}
-	else {
-		unsigned i, j, k = 0, k_last = 0;
-		unsigned partition_samples;
-		const unsigned default_partition_samples = (residual_samples+predictor_order) >> partition_order;
-		for(i = 0; i < (1u<<partition_order); i++) {
-			partition_samples = default_partition_samples;
-			if(i == 0)
-				partition_samples -= predictor_order;
-			k += partition_samples;
-			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__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__bitwriter_write_raw_int32(bw, residual[j], raw_bits[i]))
-						return false;
-				}
-			}
-			k_last = k;
-		}
-		return true;
-	}
-}
diff --git a/libFLAC/stream_encoder_intrin_avx2.c b/libFLAC/stream_encoder_intrin_avx2.c
deleted file mode 100644
index a94a02b..0000000
--- a/libFLAC/stream_encoder_intrin_avx2.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#include "private/stream_encoder.h"
-#include "private/bitmath.h"
-#ifdef FLAC__AVX2_SUPPORTED
-
-#include <stdlib.h>    /* for abs() */
-#include <immintrin.h> /* AVX2 */
-#include "FLAC/assert.h"
-
-FLAC__SSE_TARGET("avx2")
-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)
-{
-	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 */
-	{
-		const unsigned threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
-		unsigned partition, residual_sample, end = (unsigned)(-(int)predictor_order);
-
-		if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
-			for(partition = residual_sample = 0; partition < partitions; partition++) {
-				__m256i sum256 = _mm256_setzero_si256();
-				__m128i sum128;
-				end += default_partition_samples;
-
-				for( ; (int)residual_sample < (int)end-7; residual_sample+=8) {
-					__m256i res256 = _mm256_abs_epi32(_mm256_loadu_si256((const __m256i*)(residual+residual_sample)));
-					sum256 = _mm256_add_epi32(sum256, res256);
-				}
-
-				sum128 = _mm_add_epi32(_mm256_extracti128_si256(sum256, 1), _mm256_castsi256_si128(sum256));
-
-				for( ; (int)residual_sample < (int)end-3; residual_sample+=4) {
-					__m128i res128 = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(residual+residual_sample)));
-					sum128 = _mm_add_epi32(sum128, res128);
-				}
-
-				for( ; residual_sample < end; residual_sample++) {
-					__m128i res128 = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
-					sum128 = _mm_add_epi32(sum128, res128);
-				}
-
-				sum128 = _mm_hadd_epi32(sum128, sum128);
-				sum128 = _mm_hadd_epi32(sum128, sum128);
-				abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(sum128);
-/* workaround for a bug in MSVC2015U2 - see https://connect.microsoft.com/VisualStudio/feedback/details/2659191/incorrect-code-generation-for-x86-64 */
-#if (defined _MSC_VER) && (_MSC_FULL_VER == 190023918) && (defined FLAC__CPU_X86_64)
-				abs_residual_partition_sums[partition] &= 0xFFFFFFFF; /**/
-#endif
-			}
-		}
-		else { /* have to pessimistically use 64 bits for accumulator */
-			for(partition = residual_sample = 0; partition < partitions; partition++) {
-				__m256i sum256 = _mm256_setzero_si256();
-				__m128i sum128;
-				end += default_partition_samples;
-
-				for( ; (int)residual_sample < (int)end-3; residual_sample+=4) {
-					__m128i res128 = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(residual+residual_sample)));
-					__m256i res256 = _mm256_cvtepu32_epi64(res128);
-					sum256 = _mm256_add_epi64(sum256, res256);
-				}
-
-				sum128 = _mm_add_epi64(_mm256_extracti128_si256(sum256, 1), _mm256_castsi256_si128(sum256));
-
-				for( ; (int)residual_sample < (int)end-1; residual_sample+=2) {
-					__m128i res128 = _mm_abs_epi32(_mm_loadl_epi64((const __m128i*)(residual+residual_sample)));
-					res128 = _mm_cvtepu32_epi64(res128);
-					sum128 = _mm_add_epi64(sum128, res128);
-				}
-
-				for( ; residual_sample < end; residual_sample++) {
-					__m128i res128 = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
-					sum128 = _mm_add_epi64(sum128, res128);
-				}
-
-				sum128 = _mm_add_epi64(sum128, _mm_srli_si128(sum128, 8));
-				_mm_storel_epi64((__m128i*)(abs_residual_partition_sums+partition), sum128);
-			}
-		}
-	}
-
-	/* now merge partitions for lower orders */
-	{
-		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;
-			}
-		}
-	}
-	_mm256_zeroupper();
-}
-
-#endif /* FLAC__AVX2_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
diff --git a/libFLAC/stream_encoder_intrin_sse2.c b/libFLAC/stream_encoder_intrin_sse2.c
deleted file mode 100644
index 0f1d7aa..0000000
--- a/libFLAC/stream_encoder_intrin_sse2.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#include "private/stream_encoder.h"
-#include "private/bitmath.h"
-#ifdef FLAC__SSE2_SUPPORTED
-
-#include <stdlib.h>    /* for abs() */
-#include <emmintrin.h> /* SSE2 */
-#include "FLAC/assert.h"
-#include "share/compat.h"
-
-FLAC__SSE_TARGET("sse2")
-static inline __m128i local_abs_epi32(__m128i val)
-{
-	__m128i mask = _mm_srai_epi32(val, 31);
-	val = _mm_xor_si128(val, mask);
-	val = _mm_sub_epi32(val, mask);
-	return val;
-}
-
-
-FLAC__SSE_TARGET("sse2")
-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)
-{
-	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 */
-	{
-		const unsigned threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
-		unsigned partition, residual_sample, end = (unsigned)(-(int)predictor_order);
-
-		if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
-			for(partition = residual_sample = 0; partition < partitions; partition++) {
-				__m128i mm_sum = _mm_setzero_si128();
-				unsigned e1, e3;
-				end += default_partition_samples;
-
-				e1 = (residual_sample + 3) & ~3; e3 = end & ~3;
-				if(e1 > end)
-					e1 = end; /* try flac -l 1 -b 16 and you'll be here */
-
-				/* assumption: residual[] is properly aligned so (residual + e1) is properly aligned too and _mm_loadu_si128() is fast */
-				for( ; residual_sample < e1; residual_sample++) {
-					__m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
-					mm_sum = _mm_add_epi32(mm_sum, mm_res);
-				}
-
-				for( ; residual_sample < e3; residual_sample+=4) {
-					__m128i mm_res = local_abs_epi32(_mm_loadu_si128((const __m128i*)(residual+residual_sample)));
-					mm_sum = _mm_add_epi32(mm_sum, mm_res);
-				}
-
-				for( ; residual_sample < end; residual_sample++) {
-					__m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
-					mm_sum = _mm_add_epi32(mm_sum, mm_res);
-				}
-
-				mm_sum = _mm_add_epi32(mm_sum, _mm_srli_si128(mm_sum, 8));
-				mm_sum = _mm_add_epi32(mm_sum, _mm_srli_si128(mm_sum, 4));
-				abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(mm_sum);
-/* workaround for a bug in MSVC2015U2 - see https://connect.microsoft.com/VisualStudio/feedback/details/2659191/incorrect-code-generation-for-x86-64 */
-#if (defined _MSC_VER) && (_MSC_FULL_VER == 190023918) && (defined FLAC__CPU_X86_64)
-				abs_residual_partition_sums[partition] &= 0xFFFFFFFF;
-#endif
-			}
-		}
-		else { /* have to pessimistically use 64 bits for accumulator */
-			for(partition = residual_sample = 0; partition < partitions; partition++) {
-				__m128i mm_sum = _mm_setzero_si128();
-				unsigned e1, e3;
-				end += default_partition_samples;
-
-				e1 = (residual_sample + 1) & ~1; e3 = end & ~1;
-				FLAC__ASSERT(e1 <= end);
-
-				for( ; residual_sample < e1; residual_sample++) {
-					__m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); /*  0   0   0  |r0|  ==   00   |r0_64| */
-					mm_sum = _mm_add_epi64(mm_sum, mm_res);
-				}
-
-				for( ; residual_sample < e3; residual_sample+=2) {
-					__m128i mm_res = local_abs_epi32(_mm_loadl_epi64((const __m128i*)(residual+residual_sample))); /*  0   0  |r1|   |r0| */
-					mm_res = _mm_shuffle_epi32(mm_res, _MM_SHUFFLE(3,1,2,0)); /* 0  |r1|  0  |r0|  ==  |r1_64|  |r0_64|  */
-					mm_sum = _mm_add_epi64(mm_sum, mm_res);
-				}
-
-				for( ; residual_sample < end; residual_sample++) {
-					__m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
-					mm_sum = _mm_add_epi64(mm_sum, mm_res);
-				}
-
-				mm_sum = _mm_add_epi64(mm_sum, _mm_srli_si128(mm_sum, 8));
-				_mm_storel_epi64((__m128i*)(abs_residual_partition_sums+partition), mm_sum);
-			}
-		}
-	}
-
-	/* now merge partitions for lower orders */
-	{
-		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;
-			}
-		}
-	}
-}
-
-#endif /* FLAC__SSE2_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
diff --git a/libFLAC/stream_encoder_intrin_ssse3.c b/libFLAC/stream_encoder_intrin_ssse3.c
deleted file mode 100644
index 21a08fc..0000000
--- a/libFLAC/stream_encoder_intrin_ssse3.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2016  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/cpu.h"
-
-#ifndef FLAC__NO_ASM
-#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
-#include "private/stream_encoder.h"
-#include "private/bitmath.h"
-#ifdef FLAC__SSSE3_SUPPORTED
-
-#include <stdlib.h>    /* for abs() */
-#include <tmmintrin.h> /* SSSE3 */
-#include "FLAC/assert.h"
-
-FLAC__SSE_TARGET("ssse3")
-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)
-{
-	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 */
-	{
-		const unsigned threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
-		unsigned partition, residual_sample, end = (unsigned)(-(int)predictor_order);
-
-		if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
-			for(partition = residual_sample = 0; partition < partitions; partition++) {
-				__m128i mm_sum = _mm_setzero_si128();
-				unsigned e1, e3;
-				end += default_partition_samples;
-
-				e1 = (residual_sample + 3) & ~3; e3 = end & ~3;
-				if(e1 > end)
-					e1 = end; /* try flac -l 1 -b 16 and you'll be here */
-
-				/* assumption: residual[] is properly aligned so (residual + e1) is properly aligned too and _mm_loadu_si128() is fast */
-				for( ; residual_sample < e1; residual_sample++) {
-					__m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
-					mm_sum = _mm_add_epi32(mm_sum, mm_res);
-				}
-
-				for( ; residual_sample < e3; residual_sample+=4) {
-					__m128i mm_res = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(residual+residual_sample)));
-					mm_sum = _mm_add_epi32(mm_sum, mm_res);
-				}
-
-				for( ; residual_sample < end; residual_sample++) {
-					__m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
-					mm_sum = _mm_add_epi32(mm_sum, mm_res);
-				}
-
-				mm_sum = _mm_hadd_epi32(mm_sum, mm_sum);
-				mm_sum = _mm_hadd_epi32(mm_sum, mm_sum);
-				abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(mm_sum);
-/* workaround for a bug in MSVC2015U2 - see https://connect.microsoft.com/VisualStudio/feedback/details/2659191/incorrect-code-generation-for-x86-64 */
-#if (defined _MSC_VER) && (_MSC_FULL_VER == 190023918) && (defined FLAC__CPU_X86_64)
-				abs_residual_partition_sums[partition] &= 0xFFFFFFFF;
-#endif
-			}
-		}
-		else { /* have to pessimistically use 64 bits for accumulator */
-			for(partition = residual_sample = 0; partition < partitions; partition++) {
-				__m128i mm_sum = _mm_setzero_si128();
-				unsigned e1, e3;
-				end += default_partition_samples;
-
-				e1 = (residual_sample + 1) & ~1; e3 = end & ~1;
-				FLAC__ASSERT(e1 <= end);
-
-				for( ; residual_sample < e1; residual_sample++) {
-					__m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); /*  0   0   0  |r0|  ==   00   |r0_64| */
-					mm_sum = _mm_add_epi64(mm_sum, mm_res);
-				}
-
-				for( ; residual_sample < e3; residual_sample+=2) {
-					__m128i mm_res = _mm_abs_epi32(_mm_loadl_epi64((const __m128i*)(residual+residual_sample))); /*  0   0  |r1|   |r0| */
-					mm_res = _mm_shuffle_epi32(mm_res, _MM_SHUFFLE(3,1,2,0)); /* 0  |r1|  0  |r0|  ==  |r1_64|  |r0_64|  */
-					mm_sum = _mm_add_epi64(mm_sum, mm_res);
-				}
-
-				for( ; residual_sample < end; residual_sample++) {
-					__m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
-					mm_sum = _mm_add_epi64(mm_sum, mm_res);
-				}
-
-				mm_sum = _mm_add_epi64(mm_sum, _mm_srli_si128(mm_sum, 8));
-				_mm_storel_epi64((__m128i*)(abs_residual_partition_sums+partition), mm_sum);
-			}
-		}
-	}
-
-	/* now merge partitions for lower orders */
-	{
-		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;
-			}
-		}
-	}
-}
-
-#endif /* FLAC__SSSE3_SUPPORTED */
-#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
-#endif /* FLAC__NO_ASM */
diff --git a/libFLAC/window.c b/libFLAC/window.c
deleted file mode 100644
index e977fd8..0000000
--- a/libFLAC/window.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2006-2009  Josh Coalson
- * Copyright (C) 2011-2016  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 */
diff --git a/libFLAC/windows_unicode_filenames.c b/libFLAC/windows_unicode_filenames.c
deleted file mode 100644
index 2404e31..0000000
--- a/libFLAC/windows_unicode_filenames.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2013-2016  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 <io.h>
-#include "share/windows_unicode_filenames.h"
-
-/* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */
-static wchar_t *wchar_from_utf8(const char *str)
-{
-	wchar_t *widestr;
-	int len;
-
-	if (!str)
-		return NULL;
-	if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0)
-		return NULL;
-	if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) == NULL)
-		return NULL;
-	if (MultiByteToWideChar(CP_UTF8, 0, str, -1, widestr, len) == 0) {
-		free(widestr);
-		widestr = NULL;
-	}
-
-	return widestr;
-}
-
-
-static FLAC__bool utf8_filenames = false;
-
-
-void flac_internal_set_utf8_filenames(FLAC__bool flag)
-{
-	utf8_filenames = flag ? true : false;
-}
-
-FLAC__bool flac_internal_get_utf8_filenames(void)
-{
-	return utf8_filenames;
-}
-
-/* file functions */
-
-FILE* flac_internal_fopen_utf8(const char *filename, const char *mode)
-{
-	if (!utf8_filenames) {
-		return fopen(filename, mode);
-	} else {
-		wchar_t *wname = NULL;
-		wchar_t *wmode = NULL;
-		FILE *f = NULL;
-
-		do {
-			if (!(wname = wchar_from_utf8(filename))) break;
-			if (!(wmode = wchar_from_utf8(mode))) break;
-			f = _wfopen(wname, wmode);
-		} while(0);
-
-		free(wname);
-		free(wmode);
-
-		return f;
-	}
-}
-
-int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer)
-{
-	if (!utf8_filenames) {
-		return _stat64(path, buffer);
-	} else {
-		wchar_t *wpath;
-		int ret;
-
-		if (!(wpath = wchar_from_utf8(path))) return -1;
-		ret = _wstat64(wpath, buffer);
-		free(wpath);
-
-		return ret;
-	}
-}
-
-int flac_internal_chmod_utf8(const char *filename, int pmode)
-{
-	if (!utf8_filenames) {
-		return _chmod(filename, pmode);
-	} else {
-		wchar_t *wname;
-		int ret;
-
-		if (!(wname = wchar_from_utf8(filename))) return -1;
-		ret = _wchmod(wname, pmode);
-		free(wname);
-
-		return ret;
-	}
-}
-
-int flac_internal_utime_utf8(const char *filename, struct utimbuf *times)
-{
-	if (!utf8_filenames) {
-		return utime(filename, times);
-	} else {
-		wchar_t *wname;
-		struct __utimbuf64 ut;
-		int ret;
-
-		if (!(wname = wchar_from_utf8(filename))) return -1;
-		ut.actime = times->actime;
-		ut.modtime = times->modtime;
-		ret = _wutime64(wname, &ut);
-		free(wname);
-
-		return ret;
-	}
-}
-
-int flac_internal_unlink_utf8(const char *filename)
-{
-	if (!utf8_filenames) {
-		return _unlink(filename);
-	} else {
-		wchar_t *wname;
-		int ret;
-
-		if (!(wname = wchar_from_utf8(filename))) return -1;
-		ret = _wunlink(wname);
-		free(wname);
-
-		return ret;
-	}
-}
-
-int flac_internal_rename_utf8(const char *oldname, const char *newname)
-{
-	if (!utf8_filenames) {
-		return rename(oldname, newname);
-	} else {
-		wchar_t *wold = NULL;
-		wchar_t *wnew = NULL;
-		int ret = -1;
-
-		do {
-			if (!(wold = wchar_from_utf8(oldname))) break;
-			if (!(wnew = wchar_from_utf8(newname))) break;
-			ret = _wrename(wold, wnew);
-		} while(0);
-
-		free(wold);
-		free(wnew);
-
-		return ret;
-	}
-}
-
-HANDLE WINAPI flac_internal_CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
-{
-	if (!utf8_filenames) {
-		return CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
-	} else {
-		wchar_t *wname;
-		HANDLE handle = INVALID_HANDLE_VALUE;
-
-		if ((wname = wchar_from_utf8(lpFileName)) != NULL) {
-			handle = CreateFileW(wname, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
-			free(wname);
-		}
-
-		return handle;
-	}
-}
diff --git a/m4/Makefile.am b/m4/Makefile.am
new file mode 100644
index 0000000..b7952da
--- /dev/null
+++ b/m4/Makefile.am
@@ -0,0 +1,27 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2006-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+	add_cflags.m4 \
+	add_cxxflags.m4 \
+	bswap.m4 \
+	endian.m4 \
+	gcc_version.m4 \
+	ogg.m4 \
+	stack_protect.m4 \
+	xmms.m4
diff --git a/m4/add_cflags.m4 b/m4/add_cflags.m4
new file mode 100644
index 0000000..08f4a40
--- /dev/null
+++ b/m4/add_cflags.m4
@@ -0,0 +1,18 @@
+dnl @synopsis XIPH_ADD_CFLAGS
+dnl
+dnl Add the given option to CFLAGS, if it doesn't break the compiler
+
+AC_DEFUN([XIPH_ADD_CFLAGS],
+[AC_MSG_CHECKING([if $CC accepts $1])
+	ac_add_cflags__old_cflags="$CFLAGS"
+	CFLAGS="$1"
+	AC_TRY_LINK([
+			#include <stdio.h>
+			],
+		[puts("Hello, World!"); return 0;],
+		AC_MSG_RESULT([yes])
+			CFLAGS="$ac_add_cflags__old_cflags $1",
+		AC_MSG_RESULT([no])
+			CFLAGS="$ac_add_cflags__old_cflags"
+		)
+])# XIPH_ADD_CFLAGS
diff --git a/m4/add_cxxflags.m4 b/m4/add_cxxflags.m4
new file mode 100644
index 0000000..8197dc2
--- /dev/null
+++ b/m4/add_cxxflags.m4
@@ -0,0 +1,19 @@
+dnl @synopsis XIPH_ADD_CXXFLAGS
+dnl
+dnl Add the given option to CXXFLAGS, if it doesn't break the compiler
+
+AC_DEFUN([XIPH_ADD_CXXFLAGS],
+[AC_MSG_CHECKING([if $CXX accepts $1])
+	AC_LANG_ASSERT([C++])
+	ac_add_cxxflags__old_cxxflags="$CXXFLAGS"
+	CXXFLAGS="$1"
+	AC_TRY_LINK([
+			#include <cstdio>
+			],
+		[puts("Hello, World!"); return 0;],
+		AC_MSG_RESULT([yes])
+			CXXFLAGS="$ac_add_cxxflags__old_cxxflags $1",
+		AC_MSG_RESULT([no])
+			CXXFLAGS="$ac_add_cxxflags__old_cxxflags"
+		)
+])# XIPH_ADD_CXXFLAGS
diff --git a/m4/ax_add_fortify_source.m4 b/m4/ax_add_fortify_source.m4
new file mode 100644
index 0000000..d443814
--- /dev/null
+++ b/m4/ax_add_fortify_source.m4
@@ -0,0 +1,53 @@
+# ===========================================================================
+#   http://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_ADD_FORTIFY_SOURCE
+#
+# DESCRIPTION
+#
+#   Check whether -D_FORTIFY_SOURCE=2 can be added to CPPFLAGS without macro
+#   redefinition warnings. Some distributions (such as Gentoo Linux) enable
+#   _FORTIFY_SOURCE globally in their compilers, leading to unnecessary
+#   warnings in the form of
+#
+#     <command-line>:0:0: error: "_FORTIFY_SOURCE" redefined [-Werror]
+#     <built-in>: note: this is the location of the previous definition
+#
+#   which is a problem if -Werror is enabled. This macro checks whether
+#   _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2
+#   to CPPFLAGS.
+#
+# LICENSE
+#
+#   Copyright (c) 2017 David Seifert <soap@gentoo.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 1
+
+AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[
+    AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CPPFLAGS])
+    AC_LINK_IFELSE([
+        AC_LANG_SOURCE(
+            [[
+                int main() {
+                #ifndef _FORTIFY_SOURCE
+                    return 0;
+                #else
+                    this_is_an_error;
+                #endif
+                }
+            ]]
+        )], [
+            AC_MSG_RESULT([yes])
+            CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2"
+        ], [
+            AC_MSG_RESULT([no])
+    ])
+])
diff --git a/m4/ax_check_enable_debug.m4 b/m4/ax_check_enable_debug.m4
new file mode 100644
index 0000000..f99d75f
--- /dev/null
+++ b/m4/ax_check_enable_debug.m4
@@ -0,0 +1,124 @@
+# ===========================================================================
+#   http://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE])
+#
+# DESCRIPTION
+#
+#   Check for the presence of an --enable-debug option to configure, with
+#   the specified default value used when the option is not present.  Return
+#   the value in the variable $ax_enable_debug.
+#
+#   Specifying 'yes' adds '-g -O0' to the compilation flags for all
+#   languages. Specifying 'info' adds '-g' to the compilation flags.
+#   Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to
+#   the linking flags. Otherwise, nothing is added.
+#
+#   Define the variables listed in the second argument if debug is enabled,
+#   defaulting to no variables.  Defines the variables listed in the third
+#   argument if debug is disabled, defaulting to NDEBUG.  All lists of
+#   variables should be space-separated.
+#
+#   If debug is not enabled, ensure AC_PROG_* will not add debugging flags.
+#   Should be invoked prior to any AC_PROG_* compiler checks.
+#
+#   IS-RELEASE can be used to change the default to 'no' when making a
+#   release.  Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it
+#   uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE
+#   macro, there is no need to pass this parameter.
+#
+#     AX_IS_RELEASE([git-directory])
+#     AX_CHECK_ENABLE_DEBUG()
+#
+# LICENSE
+#
+#   Copyright (c) 2011 Rhys Ulerich <rhys.ulerich@gmail.com>
+#   Copyright (c) 2014, 2015 Philip Withnall <philip@tecnocode.co.uk>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.
+
+#serial 5
+
+AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[
+    AC_BEFORE([$0],[AC_PROG_CC])dnl
+    AC_BEFORE([$0],[AC_PROG_CXX])dnl
+    AC_BEFORE([$0],[AC_PROG_F77])dnl
+    AC_BEFORE([$0],[AC_PROG_FC])dnl
+
+    AC_MSG_CHECKING(whether to enable debugging)
+
+    ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1])))
+    ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],,
+                                                              [$ax_is_release],
+                                                              [$4])))
+
+    # If this is a release, override the default.
+    AS_IF([test "$ax_enable_debug_is_release" = "yes"],
+      [ax_enable_debug_default="no"])
+
+    m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))])
+    m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))])
+
+    AC_ARG_ENABLE(debug,
+	[AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])],
+	[],enable_debug=$ax_enable_debug_default)
+
+    # empty mean debug yes
+    AS_IF([test "x$enable_debug" = "x"],
+      [enable_debug="yes"])
+
+    # case of debug
+    AS_CASE([$enable_debug],
+      [yes],[
+	AC_MSG_RESULT(yes)
+	CFLAGS="${CFLAGS} -g -O0"
+	CXXFLAGS="${CXXFLAGS} -g -O0"
+	FFLAGS="${FFLAGS} -g -O0"
+	FCFLAGS="${FCFLAGS} -g -O0"
+	OBJCFLAGS="${OBJCFLAGS} -g -O0"
+      ],
+      [info],[
+	AC_MSG_RESULT(info)
+	CFLAGS="${CFLAGS} -g"
+	CXXFLAGS="${CXXFLAGS} -g"
+	FFLAGS="${FFLAGS} -g"
+	FCFLAGS="${FCFLAGS} -g"
+	OBJCFLAGS="${OBJCFLAGS} -g"
+      ],
+      [profile],[
+	AC_MSG_RESULT(profile)
+	CFLAGS="${CFLAGS} -g -pg"
+	CXXFLAGS="${CXXFLAGS} -g -pg"
+	FFLAGS="${FFLAGS} -g -pg"
+	FCFLAGS="${FCFLAGS} -g -pg"
+	OBJCFLAGS="${OBJCFLAGS} -g -pg"
+	LDFLAGS="${LDFLAGS} -pg"
+      ],
+      [
+	AC_MSG_RESULT(no)
+	dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags
+	dnl by setting any unset environment flag variables
+	AS_IF([test "x${CFLAGS+set}" != "xset"],
+	  [CFLAGS=""])
+	AS_IF([test "x${CXXFLAGS+set}" != "xset"],
+	  [CXXFLAGS=""])
+	AS_IF([test "x${FFLAGS+set}" != "xset"],
+	  [FFLAGS=""])
+	AS_IF([test "x${FCFLAGS+set}" != "xset"],
+	  [FCFLAGS=""])
+	AS_IF([test "x${OBJCFLAGS+set}" != "xset"],
+	  [OBJCFLAGS=""])
+      ])
+
+    dnl Define various variables if debugging is disabled.
+    dnl assert.h is a NOP if NDEBUG is defined, so define it by default.
+    AS_IF([test "x$enable_debug" = "xyes"],
+      [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])],
+      [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])])
+    ax_enable_debug=$enable_debug
+])
diff --git a/m4/bswap.m4 b/m4/bswap.m4
new file mode 100644
index 0000000..f504dcb
--- /dev/null
+++ b/m4/bswap.m4
@@ -0,0 +1,82 @@
+dnl Copyright (C) 2012-2014 Xiph.org Foundation
+dnl
+dnl Redistribution and use in source and binary forms, with or without
+dnl modification, are permitted provided that the following conditions
+dnl are met:
+dnl
+dnl - Redistributions of source code must retain the above copyright
+dnl notice, this list of conditions and the following disclaimer.
+dnl
+dnl - Redistributions in binary form must reproduce the above copyright
+dnl notice, this list of conditions and the following disclaimer in the
+dnl documentation and/or other materials provided with the distribution.
+dnl
+dnl - Neither the name of the Xiph.org Foundation nor the names of its
+dnl contributors may be used to endorse or promote products derived from
+dnl this software without specific prior written permission.
+dnl
+dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+dnl ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+dnl A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+dnl CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+dnl PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+dnl LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+dnl NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+dnl SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+dnl @synopsis XIPH_C_BSWAP32
+dnl
+dnl @author Erik de Castro Lopo <erikd@mega-nerd.com>
+dnl
+dnl Dtermine whether the compiler has the __builtin_bswap32() intrinsic which
+dnl is likely to be present for most versions of GCC as well as Clang.
+
+AC_DEFUN([XIPH_C_BSWAP32],
+[AC_CACHE_CHECK(for bswap32 intrinsic,
+  ac_cv_c_bswap32,
+
+  # Initialize to no
+  ac_cv_c_bswap32=no
+  HAVE_BSWAP32=0
+
+  [AC_TRY_LINK([],
+    return __builtin_bswap32 (0) ;,
+    ac_cv_c_bswap32=yes
+    HAVE_BSWAP32=1
+  )]
+  AC_DEFINE_UNQUOTED(HAVE_BSWAP32, ${HAVE_BSWAP32},
+    [Compiler has the __builtin_bswap32 intrinsic])
+
+  )]
+)# XIPH_C_BSWAP32
+
+
+dnl @synopsis XIPH_C_BSWAP16
+dnl
+dnl @author Erik de Castro Lopo <erikd@mega-nerd.com>
+dnl
+dnl Dtermine whether the compiler has the __builtin_bswap16() intrinsic which
+dnl is likely to be present for most versions of GCC as well as Clang.
+
+AC_DEFUN([XIPH_C_BSWAP16],
+[AC_CACHE_CHECK(for bswap16 intrinsic,
+  ac_cv_c_bswap16,
+
+  # Initialize to no
+  ac_cv_c_bswap16=no
+  HAVE_BSWAP16=0
+
+  [AC_TRY_LINK([],
+    return __builtin_bswap16 (0) ;,
+    ac_cv_c_bswap16=yes
+    HAVE_BSWAP16=1
+  )]
+  AC_DEFINE_UNQUOTED(HAVE_BSWAP16, ${HAVE_BSWAP16},
+    [Compiler has the __builtin_bswap16 intrinsic])
+
+  )]
+)# XIPH_C_BSWAP16
diff --git a/m4/c_attribute.m4 b/m4/c_attribute.m4
new file mode 100644
index 0000000..48aa622
--- /dev/null
+++ b/m4/c_attribute.m4
@@ -0,0 +1,18 @@
+#
+# Check for supported __attribute__ features
+#
+# AC_C_ATTRIBUTE(FEATURE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+AC_DEFUN([AC_C_ATTRIBUTE],
+[AS_VAR_PUSHDEF([CACHEVAR], [ax_cv_c_attribute_$1])dnl
+AC_CACHE_CHECK([for  __attribute__ (($1))],
+  CACHEVAR,[
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+    [[ void foo(void) __attribute__ (($1)); ]])],
+    [AS_VAR_SET(CACHEVAR, [yes])],
+    [AS_VAR_SET(CACHEVAR, [no])])])
+AS_VAR_IF(CACHEVAR,yes,
+  [m4_default([$2], :)],
+  [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl
diff --git a/m4/clang.m4 b/m4/clang.m4
new file mode 100644
index 0000000..036f0e6
--- /dev/null
+++ b/m4/clang.m4
@@ -0,0 +1,31 @@
+dnl @synopsis XIPH_C_COMPILER_IS_CLANG
+dnl
+dnl Find out if a compiler claiming to be gcc really is gcc (clang lies).
+dnl @version 1.0	Oct 31 2013
+dnl @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+dnl
+dnl Permission to use, copy, modify, distribute, and sell this file for any
+dnl purpose is hereby granted without fee, provided that the above copyright
+dnl and this permission notice appear in all copies.  No representations are
+dnl made about the suitability of this software for any purpose.  It is
+dnl provided "as is" without express or implied warranty.
+dnl
+
+
+AC_DEFUN([XIPH_C_COMPILER_IS_CLANG],
+[AC_CACHE_CHECK(whether we are using the CLANG C compiler,
+	xiph_cv_c_compiler_clang,
+	[	AC_LANG_ASSERT(C)
+		AC_TRY_LINK([
+			#include <stdio.h>
+			],
+			[
+			#ifndef __clang__
+				This is not clang!
+			#endif
+			],
+		xiph_cv_c_compiler_clang=yes,
+		xiph_cv_c_compiler_clang=no
+		])
+	)]
+)
diff --git a/m4/codeset.m4 b/m4/codeset.m4
new file mode 100644
index 0000000..cf53d24
--- /dev/null
+++ b/m4/codeset.m4
@@ -0,0 +1,23 @@
+# codeset.m4 serial 5 (gettext-0.18.2)
+dnl Copyright (C) 2000-2002, 2006, 2008-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_LANGINFO_CODESET],
+[
+  AC_CACHE_CHECK([for nl_langinfo and CODESET], [am_cv_langinfo_codeset],
+    [AC_LINK_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <langinfo.h>]],
+          [[char* cs = nl_langinfo(CODESET); return !cs;]])],
+       [am_cv_langinfo_codeset=yes],
+       [am_cv_langinfo_codeset=no])
+    ])
+  if test $am_cv_langinfo_codeset = yes; then
+    AC_DEFINE([HAVE_LANGINFO_CODESET], [1],
+      [Define if you have <langinfo.h> and nl_langinfo(CODESET).])
+  fi
+])
diff --git a/m4/endian.m4 b/m4/endian.m4
new file mode 100644
index 0000000..330a17f
--- /dev/null
+++ b/m4/endian.m4
@@ -0,0 +1,177 @@
+dnl Copyright (C) 2012-2016  Xiph.org Foundation
+dnl
+dnl Redistribution and use in source and binary forms, with or without
+dnl modification, are permitted provided that the following conditions
+dnl are met:
+dnl
+dnl - Redistributions of source code must retain the above copyright
+dnl notice, this list of conditions and the following disclaimer.
+dnl
+dnl - Redistributions in binary form must reproduce the above copyright
+dnl notice, this list of conditions and the following disclaimer in the
+dnl documentation and/or other materials provided with the distribution.
+dnl
+dnl - Neither the name of the Xiph.org Foundation nor the names of its
+dnl contributors may be used to endorse or promote products derived from
+dnl this software without specific prior written permission.
+dnl
+dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+dnl ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+dnl A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+dnl CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+dnl PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+dnl LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+dnl NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+dnl SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+dnl @synopsis XIPH_C_FIND_ENDIAN
+dnl
+dnl Determine endian-ness of target processor.
+dnl @version 1.1	Mar 03 2002
+dnl @author Erik de Castro Lopo <erikd@mega-nerd.com>
+dnl
+dnl Majority written from scratch to replace the standard autoconf macro
+dnl AC_C_BIGENDIAN. Only part remaining from the original is the invocation
+dnl of the AC_TRY_RUN macro.
+dnl
+dnl Find endian-ness in the following way:
+dnl    1) Look in <endian.h>.
+dnl    2) If 1) fails, look in <sys/types.h> and <sys/param.h>.
+dnl    3) If 1) and 2) fails and not cross compiling run a test program.
+dnl    4) If 1) and 2) fails and cross compiling then guess based on target.
+
+AC_DEFUN([XIPH_C_FIND_ENDIAN],
+[AC_CACHE_CHECK(processor byte ordering,
+	ac_cv_c_byte_order,
+
+# Initialize to unknown
+ac_cv_c_byte_order=unknown
+
+if test x$ac_cv_header_endian_h = xyes ; then
+
+	# First try <endian.h> which should set BYTE_ORDER.
+
+	[AC_TRY_LINK([
+		#include <endian.h>
+		#if BYTE_ORDER != LITTLE_ENDIAN
+			not big endian
+		#endif
+		], return 0 ;,
+			ac_cv_c_byte_order=little
+		)]
+
+	[AC_TRY_LINK([
+		#include <endian.h>
+		#if BYTE_ORDER != BIG_ENDIAN
+			not big endian
+		#endif
+		], return 0 ;,
+			ac_cv_c_byte_order=big
+		)]
+
+	fi
+
+if test $ac_cv_c_byte_order = unknown ; then
+
+	[AC_TRY_LINK([
+		#include <sys/types.h>
+		#include <sys/param.h>
+		#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+			bogus endian macros
+		#endif
+		], return 0 ;,
+
+		[AC_TRY_LINK([
+			#include <sys/types.h>
+			#include <sys/param.h>
+			#if BYTE_ORDER != LITTLE_ENDIAN
+				not big endian
+			#endif
+			], return 0 ;,
+				ac_cv_c_byte_order=little
+			)]
+
+		[AC_TRY_LINK([
+			#include <sys/types.h>
+			#include <sys/param.h>
+			#if BYTE_ORDER != LITTLE_ENDIAN
+				not big endian
+			#endif
+			], return 0 ;,
+				ac_cv_c_byte_order=little
+			)]
+
+		)]
+
+ 	fi
+
+if test $ac_cv_c_byte_order = unknown ; then
+	if test $cross_compiling = yes ; then
+		# This is the last resort. Try to guess the target processor endian-ness
+		# by looking at the target CPU type.
+		[
+		case "$target_cpu" in
+			alpha* | i?86* | mipsel* | ia64*)
+				ac_cv_c_byte_order=little
+				;;
+
+			m68* | mips* | powerpc* | hppa* | sparc*)
+				ac_cv_c_byte_order=big
+				;;
+
+			esac
+		]
+	else
+		AC_TRY_RUN(
+		[[
+		int main (void)
+		{	/* Are we little or big endian?  From Harbison&Steele.  */
+			union
+			{	long l ;
+				char c [sizeof (long)] ;
+			} u ;
+			u.l = 1 ;
+			return (u.c [sizeof (long) - 1] == 1);
+			}
+			]], , ac_cv_c_byte_order=big,
+			)
+
+		AC_TRY_RUN(
+		[[int main (void)
+		{	/* Are we little or big endian?  From Harbison&Steele.  */
+			union
+			{	long l ;
+				char c [sizeof (long)] ;
+			} u ;
+			u.l = 1 ;
+			return (u.c [0] == 1);
+			}]], , ac_cv_c_byte_order=little,
+			)
+		fi
+	fi
+
+)
+
+if test $ac_cv_c_byte_order = big ; then
+	ac_cv_c_big_endian=1
+	ac_cv_c_little_endian=0
+elif test $ac_cv_c_byte_order = little ; then
+	ac_cv_c_big_endian=0
+	ac_cv_c_little_endian=1
+else
+	ac_cv_c_big_endian=0
+	ac_cv_c_little_endian=0
+
+	AC_MSG_WARN([[*****************************************************************]])
+	AC_MSG_WARN([[*** Not able to determine endian-ness of target processor.       ]])
+	AC_MSG_WARN([[*** The constants CPU_IS_BIG_ENDIAN and CPU_IS_LITTLE_ENDIAN in  ]])
+	AC_MSG_WARN([[*** config.h may need to be hand editied.                        ]])
+	AC_MSG_WARN([[*****************************************************************]])
+	fi
+
+]
+)# XIPH_C_FIND_ENDIAN
diff --git a/m4/gcc_version.m4 b/m4/gcc_version.m4
new file mode 100644
index 0000000..e6aaa60
--- /dev/null
+++ b/m4/gcc_version.m4
@@ -0,0 +1,34 @@
+dnl @synopsis XIPH_GCC_VERSION
+dnl
+dnl Find the version of gcc.
+dnl @version 1.0	Nov 05 2007
+dnl @version 1.1	Mar 10 2013
+dnl @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+dnl
+dnl Permission to use, copy, modify, distribute, and sell this file for any
+dnl purpose is hereby granted without fee, provided that the above copyright
+dnl and this permission notice appear in all copies.  No representations are
+dnl made about the suitability of this software for any purpose.  It is
+dnl provided "as is" without express or implied warranty.
+dnl
+
+AC_DEFUN([XIPH_GCC_VERSION],
+[
+if test "x$ac_cv_c_compiler_gnu" = "xyes" ; then
+
+	AC_MSG_CHECKING([for version of $CC])
+	GCC_VERSION=`$CC -dumpversion`
+	AC_MSG_RESULT($GCC_VERSION)
+
+	GCC_MAJOR_VERSION=`echo $GCC_VERSION | cut -d. -f 1`
+	GCC_MINOR_VERSION=`echo $GCC_VERSION | cut -d. -f 2`
+else
+	GCC_MAJOR_VERSION=0
+	GCC_MINOR_VERSION=0
+	fi
+
+AC_SUBST(GCC_VERSION)
+AC_SUBST(GCC_MAJOR_VERSION)
+AC_SUBST(GCC_MINOR_VERSION)
+
+])# XIPH_GCC_VERSION
diff --git a/m4/iconv.m4 b/m4/iconv.m4
new file mode 100644
index 0000000..6a47236
--- /dev/null
+++ b/m4/iconv.m4
@@ -0,0 +1,268 @@
+# iconv.m4 serial 18 (gettext-0.18.2)
+dnl Copyright (C) 2000-2002, 2007-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
+[
+  dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([iconv])
+])
+
+AC_DEFUN([AM_ICONV_LINK],
+[
+  dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+  dnl those with the standalone portable GNU libiconv installed).
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+
+  dnl Add $INCICONV to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed libiconv and not disabled its use
+  dnl via --without-libiconv-prefix, he wants to use it. The first
+  dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed.
+  am_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV])
+
+  AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [
+    am_cv_func_iconv="no, consider installing GNU libiconv"
+    am_cv_lib_iconv=no
+    AC_LINK_IFELSE(
+      [AC_LANG_PROGRAM(
+         [[
+#include <stdlib.h>
+#include <iconv.h>
+         ]],
+         [[iconv_t cd = iconv_open("","");
+           iconv(cd,NULL,NULL,NULL,NULL);
+           iconv_close(cd);]])],
+      [am_cv_func_iconv=yes])
+    if test "$am_cv_func_iconv" != yes; then
+      am_save_LIBS="$LIBS"
+      LIBS="$LIBS $LIBICONV"
+      AC_LINK_IFELSE(
+        [AC_LANG_PROGRAM(
+           [[
+#include <stdlib.h>
+#include <iconv.h>
+           ]],
+           [[iconv_t cd = iconv_open("","");
+             iconv(cd,NULL,NULL,NULL,NULL);
+             iconv_close(cd);]])],
+        [am_cv_lib_iconv=yes]
+        [am_cv_func_iconv=yes])
+      LIBS="$am_save_LIBS"
+    fi
+  ])
+  if test "$am_cv_func_iconv" = yes; then
+    AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [
+      dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11,
+      dnl Solaris 10.
+      am_save_LIBS="$LIBS"
+      if test $am_cv_lib_iconv = yes; then
+        LIBS="$LIBS $LIBICONV"
+      fi
+      AC_RUN_IFELSE(
+        [AC_LANG_SOURCE([[
+#include <iconv.h>
+#include <string.h>
+int main ()
+{
+  int result = 0;
+  /* Test against AIX 5.1 bug: Failures are not distinguishable from successful
+     returns.  */
+  {
+    iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
+    if (cd_utf8_to_88591 != (iconv_t)(-1))
+      {
+        static const char input[] = "\342\202\254"; /* EURO SIGN */
+        char buf[10];
+        const char *inptr = input;
+        size_t inbytesleft = strlen (input);
+        char *outptr = buf;
+        size_t outbytesleft = sizeof (buf);
+        size_t res = iconv (cd_utf8_to_88591,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if (res == 0)
+          result |= 1;
+        iconv_close (cd_utf8_to_88591);
+      }
+  }
+  /* Test against Solaris 10 bug: Failures are not distinguishable from
+     successful returns.  */
+  {
+    iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646");
+    if (cd_ascii_to_88591 != (iconv_t)(-1))
+      {
+        static const char input[] = "\263";
+        char buf[10];
+        const char *inptr = input;
+        size_t inbytesleft = strlen (input);
+        char *outptr = buf;
+        size_t outbytesleft = sizeof (buf);
+        size_t res = iconv (cd_ascii_to_88591,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if (res == 0)
+          result |= 2;
+        iconv_close (cd_ascii_to_88591);
+      }
+  }
+  /* Test against AIX 6.1..7.1 bug: Buffer overrun.  */
+  {
+    iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1");
+    if (cd_88591_to_utf8 != (iconv_t)(-1))
+      {
+        static const char input[] = "\304";
+        static char buf[2] = { (char)0xDE, (char)0xAD };
+        const char *inptr = input;
+        size_t inbytesleft = 1;
+        char *outptr = buf;
+        size_t outbytesleft = 1;
+        size_t res = iconv (cd_88591_to_utf8,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD)
+          result |= 4;
+        iconv_close (cd_88591_to_utf8);
+      }
+  }
+#if 0 /* This bug could be worked around by the caller.  */
+  /* Test against HP-UX 11.11 bug: Positive return value instead of 0.  */
+  {
+    iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591");
+    if (cd_88591_to_utf8 != (iconv_t)(-1))
+      {
+        static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
+        char buf[50];
+        const char *inptr = input;
+        size_t inbytesleft = strlen (input);
+        char *outptr = buf;
+        size_t outbytesleft = sizeof (buf);
+        size_t res = iconv (cd_88591_to_utf8,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if ((int)res > 0)
+          result |= 8;
+        iconv_close (cd_88591_to_utf8);
+      }
+  }
+#endif
+  /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
+     provided.  */
+  if (/* Try standardized names.  */
+      iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
+      /* Try IRIX, OSF/1 names.  */
+      && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
+      /* Try AIX names.  */
+      && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
+      /* Try HP-UX names.  */
+      && iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
+    result |= 16;
+  return result;
+}]])],
+        [am_cv_func_iconv_works=yes],
+        [am_cv_func_iconv_works=no],
+        [
+changequote(,)dnl
+         case "$host_os" in
+           aix* | hpux*) am_cv_func_iconv_works="guessing no" ;;
+           *)            am_cv_func_iconv_works="guessing yes" ;;
+         esac
+changequote([,])dnl
+        ])
+      LIBS="$am_save_LIBS"
+    ])
+    case "$am_cv_func_iconv_works" in
+      *no) am_func_iconv=no am_cv_lib_iconv=no ;;
+      *)   am_func_iconv=yes ;;
+    esac
+  else
+    am_func_iconv=no am_cv_lib_iconv=no
+  fi
+  if test "$am_func_iconv" = yes; then
+    AC_DEFINE([HAVE_ICONV], [1],
+      [Define if you have the iconv() function and it works.])
+  fi
+  if test "$am_cv_lib_iconv" = yes; then
+    AC_MSG_CHECKING([how to link with libiconv])
+    AC_MSG_RESULT([$LIBICONV])
+  else
+    dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV
+    dnl either.
+    CPPFLAGS="$am_save_CPPFLAGS"
+    LIBICONV=
+    LTLIBICONV=
+  fi
+  AC_SUBST([LIBICONV])
+  AC_SUBST([LTLIBICONV])
+])
+
+dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to
+dnl avoid warnings like
+dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required".
+dnl This is tricky because of the way 'aclocal' is implemented:
+dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN.
+dnl   Otherwise aclocal's initial scan pass would miss the macro definition.
+dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions.
+dnl   Otherwise aclocal would emit many "Use of uninitialized value $1"
+dnl   warnings.
+m4_define([gl_iconv_AC_DEFUN],
+  m4_version_prereq([2.64],
+    [[AC_DEFUN_ONCE(
+        [$1], [$2])]],
+    [m4_ifdef([gl_00GNULIB],
+       [[AC_DEFUN_ONCE(
+           [$1], [$2])]],
+       [[AC_DEFUN(
+           [$1], [$2])]])]))
+gl_iconv_AC_DEFUN([AM_ICONV],
+[
+  AM_ICONV_LINK
+  if test "$am_cv_func_iconv" = yes; then
+    AC_MSG_CHECKING([for iconv declaration])
+    AC_CACHE_VAL([am_cv_proto_iconv], [
+      AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM(
+           [[
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+           ]],
+           [[]])],
+        [am_cv_proto_iconv_arg1=""],
+        [am_cv_proto_iconv_arg1="const"])
+      am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+    am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+    AC_MSG_RESULT([
+         $am_cv_proto_iconv])
+    AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1],
+      [Define as const if the declaration of iconv() needs const.])
+    dnl Also substitute ICONV_CONST in the gnulib generated <iconv.h>.
+    m4_ifdef([gl_ICONV_H_DEFAULTS],
+      [AC_REQUIRE([gl_ICONV_H_DEFAULTS])
+       if test -n "$am_cv_proto_iconv_arg1"; then
+         ICONV_CONST="const"
+       fi
+      ])
+  fi
+])
diff --git a/m4/lib-ld.m4 b/m4/lib-ld.m4
new file mode 100644
index 0000000..e1feab5
--- /dev/null
+++ b/m4/lib-ld.m4
@@ -0,0 +1,119 @@
+# lib-ld.m4 serial 6
+dnl Copyright (C) 1996-2003, 2009-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Subroutines of libtool.m4,
+dnl with replacements s/_*LT_PATH/AC_LIB_PROG/ and s/lt_/acl_/ to avoid
+dnl collision with libtool.m4.
+
+dnl From libtool-2.4. Sets the variable with_gnu_ld to yes or no.
+AC_DEFUN([AC_LIB_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld],
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  acl_cv_prog_gnu_ld=yes
+  ;;
+*)
+  acl_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-2.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+        [assume the C compiler uses GNU ld [default=no]])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which
+  # contains only /bin. Note that ksh looks also at the FPATH variable,
+  # so we have to set that as well for the test.
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \
+    && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \
+           || PATH_SEPARATOR=';'
+       }
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'`
+      while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do
+        ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL([acl_cv_path_LD],
+[if test -z "$LD"; then
+  acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$acl_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      acl_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$acl_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+        test "$with_gnu_ld" != no && break
+        ;;
+      *)
+        test "$with_gnu_ld" != yes && break
+        ;;
+      esac
+    fi
+  done
+  IFS="$acl_save_ifs"
+else
+  acl_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$acl_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT([$LD])
+else
+  AC_MSG_RESULT([no])
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_LIB_PROG_LD_GNU
+])
diff --git a/m4/lib-link.m4 b/m4/lib-link.m4
new file mode 100644
index 0000000..d11b4b4
--- /dev/null
+++ b/m4/lib-link.m4
@@ -0,0 +1,777 @@
+# lib-link.m4 serial 26 (gettext-0.18.2)
+dnl Copyright (C) 2001-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_PREREQ([2.54])
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
+dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  pushdef([Name],[m4_translit([$1],[./+-], [____])])
+  pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-],
+                                   [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])])
+  AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+    AC_LIB_LINKFLAGS_BODY([$1], [$2])
+    ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+    ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+    ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+    ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX"
+  ])
+  LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+  LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+  INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+  LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  AC_SUBST([LIB]NAME[_PREFIX])
+  dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+  dnl results of this search when this library appears as a dependency.
+  HAVE_LIB[]NAME=yes
+  popdef([NAME])
+  popdef([Name])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode, [missing-message])
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. The missing-message
+dnl defaults to 'no' and may contain additional hints for the user.
+dnl If found, it sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME}
+dnl and LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
+dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  pushdef([Name],[m4_translit([$1],[./+-], [____])])
+  pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-],
+                                   [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])])
+
+  dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+  dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed lib[]Name and not disabled its use
+  dnl via --without-lib[]Name-prefix, he wants to use it.
+  ac_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+  AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+    ac_save_LIBS="$LIBS"
+    dnl If $LIB[]NAME contains some -l options, add it to the end of LIBS,
+    dnl because these -l options might require -L options that are present in
+    dnl LIBS. -l options benefit only from the -L options listed before it.
+    dnl Otherwise, add it to the front of LIBS, because it may be a static
+    dnl library that depends on another static library that is present in LIBS.
+    dnl Static libraries benefit only from the static libraries listed after
+    dnl it.
+    case " $LIB[]NAME" in
+      *" -l"*) LIBS="$LIBS $LIB[]NAME" ;;
+      *)       LIBS="$LIB[]NAME $LIBS" ;;
+    esac
+    AC_LINK_IFELSE(
+      [AC_LANG_PROGRAM([[$3]], [[$4]])],
+      [ac_cv_lib[]Name=yes],
+      [ac_cv_lib[]Name='m4_if([$5], [], [no], [[$5]])'])
+    LIBS="$ac_save_LIBS"
+  ])
+  if test "$ac_cv_lib[]Name" = yes; then
+    HAVE_LIB[]NAME=yes
+    AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the lib][$1 library.])
+    AC_MSG_CHECKING([how to link with lib[]$1])
+    AC_MSG_RESULT([$LIB[]NAME])
+  else
+    HAVE_LIB[]NAME=no
+    dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+    dnl $INC[]NAME either.
+    CPPFLAGS="$ac_save_CPPFLAGS"
+    LIB[]NAME=
+    LTLIB[]NAME=
+    LIB[]NAME[]_PREFIX=
+  fi
+  AC_SUBST([HAVE_LIB]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  AC_SUBST([LIB]NAME[_PREFIX])
+  popdef([NAME])
+  popdef([Name])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl   acl_libext,
+dnl   acl_shlibext,
+dnl   acl_libname_spec,
+dnl   acl_library_names_spec,
+dnl   acl_hardcode_libdir_flag_spec,
+dnl   acl_hardcode_libdir_separator,
+dnl   acl_hardcode_direct,
+dnl   acl_hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+  dnl Tell automake >= 1.10 to complain if config.rpath is missing.
+  m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
+  AC_REQUIRE([AC_PROG_CC])                dnl we use $CC, $GCC, $LDFLAGS
+  AC_REQUIRE([AC_LIB_PROG_LD])            dnl we use $LD, $with_gnu_ld
+  AC_REQUIRE([AC_CANONICAL_HOST])         dnl we use $host
+  AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+  AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [
+    CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+    ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+    . ./conftest.sh
+    rm -f ./conftest.sh
+    acl_cv_rpath=done
+  ])
+  wl="$acl_cv_wl"
+  acl_libext="$acl_cv_libext"
+  acl_shlibext="$acl_cv_shlibext"
+  acl_libname_spec="$acl_cv_libname_spec"
+  acl_library_names_spec="$acl_cv_library_names_spec"
+  acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+  acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+  acl_hardcode_direct="$acl_cv_hardcode_direct"
+  acl_hardcode_minus_L="$acl_cv_hardcode_minus_L"
+  dnl Determine whether the user wants rpath handling at all.
+  AC_ARG_ENABLE([rpath],
+    [  --disable-rpath         do not hardcode runtime library paths],
+    :, enable_rpath=yes)
+])
+
+dnl AC_LIB_FROMPACKAGE(name, package)
+dnl declares that libname comes from the given package. The configure file
+dnl will then not have a --with-libname-prefix option but a
+dnl --with-package-prefix option. Several libraries can come from the same
+dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar
+dnl macro call that searches for libname.
+AC_DEFUN([AC_LIB_FROMPACKAGE],
+[
+  pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-],
+                                   [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])])
+  define([acl_frompackage_]NAME, [$2])
+  popdef([NAME])
+  pushdef([PACK],[$2])
+  pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-],
+                                     [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])])
+  define([acl_libsinpackage_]PACKUP,
+    m4_ifdef([acl_libsinpackage_]PACKUP, [m4_defn([acl_libsinpackage_]PACKUP)[, ]],)[lib$1])
+  popdef([PACKUP])
+  popdef([PACK])
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found
+dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-],
+                                   [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])])
+  pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])])
+  pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-],
+                                     [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])])
+  pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])])
+  dnl Autoconf >= 2.61 supports dots in --with options.
+  pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[m4_translit(PACK,[.],[_])],PACK)])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_ARG_WITH(P_A_C_K[-prefix],
+[[  --with-]]P_A_C_K[[-prefix[=DIR]  search for ]PACKLIBS[ in DIR/include and DIR/lib
+  --without-]]P_A_C_K[[-prefix     don't search for ]PACKLIBS[ in includedir and libdir]],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/$acl_libdirstem"
+        if test "$acl_libdirstem2" != "$acl_libdirstem" \
+           && ! test -d "$withval/$acl_libdirstem"; then
+          additional_libdir="$withval/$acl_libdirstem2"
+        fi
+      fi
+    fi
+])
+  dnl Search the library and its dependencies in $additional_libdir and
+  dnl $LDFLAGS. Using breadth-first-seach.
+  LIB[]NAME=
+  LTLIB[]NAME=
+  INC[]NAME=
+  LIB[]NAME[]_PREFIX=
+  dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been
+  dnl computed. So it has to be reset here.
+  HAVE_LIB[]NAME=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='$1 $2'
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+        dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+        dnl or AC_LIB_HAVE_LINKFLAGS call.
+        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+          else
+            dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+            dnl that this library doesn't exist. So just drop it.
+            :
+          fi
+        else
+          dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+          dnl and the already constructed $LIBNAME/$LTLIBNAME.
+          found_dir=
+          found_la=
+          found_so=
+          found_a=
+          eval libname=\"$acl_libname_spec\"    # typically: libname=lib$name
+          if test -n "$acl_shlibext"; then
+            shrext=".$acl_shlibext"             # typically: shrext=.so
+          else
+            shrext=
+          fi
+          if test $use_additional = yes; then
+            dir="$additional_libdir"
+            dnl The same code as in the loop below:
+            dnl First look for a shared library.
+            if test -n "$acl_shlibext"; then
+              if test -f "$dir/$libname$shrext"; then
+                found_dir="$dir"
+                found_so="$dir/$libname$shrext"
+              else
+                if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+                  ver=`(cd "$dir" && \
+                        for f in "$libname$shrext".*; do echo "$f"; done \
+                        | sed -e "s,^$libname$shrext\\\\.,," \
+                        | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+                        | sed 1q ) 2>/dev/null`
+                  if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+                    found_dir="$dir"
+                    found_so="$dir/$libname$shrext.$ver"
+                  fi
+                else
+                  eval library_names=\"$acl_library_names_spec\"
+                  for f in $library_names; do
+                    if test -f "$dir/$f"; then
+                      found_dir="$dir"
+                      found_so="$dir/$f"
+                      break
+                    fi
+                  done
+                fi
+              fi
+            fi
+            dnl Then look for a static library.
+            if test "X$found_dir" = "X"; then
+              if test -f "$dir/$libname.$acl_libext"; then
+                found_dir="$dir"
+                found_a="$dir/$libname.$acl_libext"
+              fi
+            fi
+            if test "X$found_dir" != "X"; then
+              if test -f "$dir/$libname.la"; then
+                found_la="$dir/$libname.la"
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIB[]NAME; do
+              AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  dnl First look for a shared library.
+                  if test -n "$acl_shlibext"; then
+                    if test -f "$dir/$libname$shrext"; then
+                      found_dir="$dir"
+                      found_so="$dir/$libname$shrext"
+                    else
+                      if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+                        ver=`(cd "$dir" && \
+                              for f in "$libname$shrext".*; do echo "$f"; done \
+                              | sed -e "s,^$libname$shrext\\\\.,," \
+                              | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+                              | sed 1q ) 2>/dev/null`
+                        if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+                          found_dir="$dir"
+                          found_so="$dir/$libname$shrext.$ver"
+                        fi
+                      else
+                        eval library_names=\"$acl_library_names_spec\"
+                        for f in $library_names; do
+                          if test -f "$dir/$f"; then
+                            found_dir="$dir"
+                            found_so="$dir/$f"
+                            break
+                          fi
+                        done
+                      fi
+                    fi
+                  fi
+                  dnl Then look for a static library.
+                  if test "X$found_dir" = "X"; then
+                    if test -f "$dir/$libname.$acl_libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/$libname.$acl_libext"
+                    fi
+                  fi
+                  if test "X$found_dir" != "X"; then
+                    if test -f "$dir/$libname.la"; then
+                      found_la="$dir/$libname.la"
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+            dnl Found the library.
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+              dnl Linking with a shared library. We attempt to hardcode its
+              dnl directory into the executable's runpath, unless it's the
+              dnl standard /usr/lib.
+              if test "$enable_rpath" = no \
+                 || test "X$found_dir" = "X/usr/$acl_libdirstem" \
+                 || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then
+                dnl No hardcoding is needed.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+              else
+                dnl Use an explicit option to hardcode DIR into the resulting
+                dnl binary.
+                dnl Potentially add DIR to ltrpathdirs.
+                dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                dnl The hardcoding into $LIBNAME is system dependent.
+                if test "$acl_hardcode_direct" = yes; then
+                  dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+                  dnl resulting binary.
+                  LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                else
+                  if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
+                    dnl Use an explicit option to hardcode DIR into the resulting
+                    dnl binary.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    dnl Potentially add DIR to rpathdirs.
+                    dnl The rpathdirs will be appended to $LIBNAME at the end.
+                    haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                    dnl Rely on "-L$found_dir".
+                    dnl But don't add it if it's already contained in the LDFLAGS
+                    dnl or the already constructed $LIBNAME
+                    haveit=
+                    for x in $LDFLAGS $LIB[]NAME; do
+                      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+                    fi
+                    if test "$acl_hardcode_minus_L" != no; then
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    else
+                      dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH
+                      dnl here, because this doesn't fit in flags passed to the
+                      dnl compiler. So give up. No hardcoding. This affects only
+                      dnl very old systems.
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                dnl Linking with a static library.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+              else
+                dnl We shouldn't come here, but anyway it's good to have a
+                dnl fallback.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+              fi
+            fi
+            dnl Assume the include files are nearby.
+            additional_includedir=
+            case "$found_dir" in
+              */$acl_libdirstem | */$acl_libdirstem/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
+                if test "$name" = '$1'; then
+                  LIB[]NAME[]_PREFIX="$basedir"
+                fi
+                additional_includedir="$basedir/include"
+                ;;
+              */$acl_libdirstem2 | */$acl_libdirstem2/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'`
+                if test "$name" = '$1'; then
+                  LIB[]NAME[]_PREFIX="$basedir"
+                fi
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+              dnl Potentially add $additional_includedir to $INCNAME.
+              dnl But don't add it
+              dnl   1. if it's the standard /usr/include,
+              dnl   2. if it's /usr/local/include and we are using GCC on Linux,
+              dnl   3. if it's already present in $CPPFLAGS or the already
+              dnl      constructed $INCNAME,
+              dnl   4. if it doesn't exist as a directory.
+              if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INC[]NAME; do
+                    AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                      dnl Really add $additional_includedir to $INCNAME.
+                      INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+            dnl Look for dependencies.
+            if test -n "$found_la"; then
+              dnl Read the .la file. It defines the variables
+              dnl dlname, library_names, old_library, dependency_libs, current,
+              dnl age, revision, installed, dlopen, dlpreopen, libdir.
+              save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+              dnl We use only dependency_libs.
+              for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                    dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+                    dnl But don't add it
+                    dnl   1. if it's the standard /usr/lib,
+                    dnl   2. if it's /usr/local/lib and we are using GCC on Linux,
+                    dnl   3. if it's already present in $LDFLAGS or the already
+                    dnl      constructed $LIBNAME,
+                    dnl   4. if it doesn't exist as a directory.
+                    if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \
+                       && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \
+                         || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LIBNAME.
+                            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LTLIBNAME.
+                            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                      dnl Potentially add DIR to rpathdirs.
+                      dnl The rpathdirs will be appended to $LIBNAME at the end.
+                      haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                      dnl Potentially add DIR to ltrpathdirs.
+                      dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                      haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                    dnl Handle this in the next round.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                    dnl Handle this in the next round. Throw away the .la's
+                    dnl directory; it is already contained in a preceding -L
+                    dnl option.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                    dnl Most likely an immediate library name.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+                    LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+            dnl Didn't find the library; assume it is in the system directories
+            dnl known to the linker and runtime loader. (All the system
+            dnl directories known to the linker should also be known to the
+            dnl runtime loader, otherwise the system is severely misconfigured.)
+            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$acl_hardcode_libdir_separator"; then
+      dnl Weird platform: only the last -rpath option counts, the user must
+      dnl pass all path elements in one option. We can arrange that for a
+      dnl single library, but not when more than one $LIBNAMEs are used.
+      alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir"
+      done
+      dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl.
+      acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$acl_hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+    else
+      dnl The -rpath options are cumulative.
+      for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$acl_hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+    dnl When using libtool, the option that works for both libraries and
+    dnl executables is -R. The -R options are cumulative.
+    for found_dir in $ltrpathdirs; do
+      LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+    done
+  fi
+  popdef([P_A_C_K])
+  popdef([PACKLIBS])
+  popdef([PACKUP])
+  popdef([PACK])
+  popdef([NAME])
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+  for element in [$2]; do
+    haveit=
+    for x in $[$1]; do
+      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      [$1]="${[$1]}${[$1]:+ }$element"
+    fi
+  done
+])
+
+dnl For those cases where a variable contains several -L and -l options
+dnl referring to unknown libraries and directories, this macro determines the
+dnl necessary additional linker options for the runtime path.
+dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL])
+dnl sets LDADDVAR to linker options needed together with LIBSVALUE.
+dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed,
+dnl otherwise linking without libtool is assumed.
+AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS],
+[
+  AC_REQUIRE([AC_LIB_RPATH])
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  $1=
+  if test "$enable_rpath" != no; then
+    if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
+      dnl Use an explicit option to hardcode directories into the resulting
+      dnl binary.
+      rpathdirs=
+      next=
+      for opt in $2; do
+        if test -n "$next"; then
+          dir="$next"
+          dnl No need to hardcode the standard /usr/lib.
+          if test "X$dir" != "X/usr/$acl_libdirstem" \
+             && test "X$dir" != "X/usr/$acl_libdirstem2"; then
+            rpathdirs="$rpathdirs $dir"
+          fi
+          next=
+        else
+          case $opt in
+            -L) next=yes ;;
+            -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'`
+                 dnl No need to hardcode the standard /usr/lib.
+                 if test "X$dir" != "X/usr/$acl_libdirstem" \
+                    && test "X$dir" != "X/usr/$acl_libdirstem2"; then
+                   rpathdirs="$rpathdirs $dir"
+                 fi
+                 next= ;;
+            *) next= ;;
+          esac
+        fi
+      done
+      if test "X$rpathdirs" != "X"; then
+        if test -n ""$3""; then
+          dnl libtool is used for linking. Use -R options.
+          for dir in $rpathdirs; do
+            $1="${$1}${$1:+ }-R$dir"
+          done
+        else
+          dnl The linker is used for linking directly.
+          if test -n "$acl_hardcode_libdir_separator"; then
+            dnl Weird platform: only the last -rpath option counts, the user
+            dnl must pass all path elements in one option.
+            alldirs=
+            for dir in $rpathdirs; do
+              alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir"
+            done
+            acl_save_libdir="$libdir"
+            libdir="$alldirs"
+            eval flag=\"$acl_hardcode_libdir_flag_spec\"
+            libdir="$acl_save_libdir"
+            $1="$flag"
+          else
+            dnl The -rpath options are cumulative.
+            for dir in $rpathdirs; do
+              acl_save_libdir="$libdir"
+              libdir="$dir"
+              eval flag=\"$acl_hardcode_libdir_flag_spec\"
+              libdir="$acl_save_libdir"
+              $1="${$1}${$1:+ }$flag"
+            done
+          fi
+        fi
+      fi
+    fi
+  fi
+  AC_SUBST([$1])
+])
diff --git a/m4/lib-prefix.m4 b/m4/lib-prefix.m4
new file mode 100644
index 0000000..007aa05
--- /dev/null
+++ b/m4/lib-prefix.m4
@@ -0,0 +1,224 @@
+# lib-prefix.m4 serial 7 (gettext-0.18)
+dnl Copyright (C) 2001-2005, 2008-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
+dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
+dnl require excessive bracketing.
+ifdef([AC_HELP_STRING],
+[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
+[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
+
+dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
+dnl to access previously installed libraries. The basic assumption is that
+dnl a user will want packages to use other packages he previously installed
+dnl with the same --prefix option.
+dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
+dnl libraries, but is otherwise very convenient.
+AC_DEFUN([AC_LIB_PREFIX],
+[
+  AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_LIB_ARG_WITH([lib-prefix],
+[  --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+  --without-lib-prefix    don't search for libraries in includedir and libdir],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/$acl_libdirstem"
+      fi
+    fi
+])
+  if test $use_additional = yes; then
+    dnl Potentially add $additional_includedir to $CPPFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/include,
+    dnl   2. if it's already present in $CPPFLAGS,
+    dnl   3. if it's /usr/local/include and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_includedir" != "X/usr/include"; then
+      haveit=
+      for x in $CPPFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-I$additional_includedir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_includedir" = "X/usr/local/include"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_includedir"; then
+            dnl Really add $additional_includedir to $CPPFLAGS.
+            CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
+          fi
+        fi
+      fi
+    fi
+    dnl Potentially add $additional_libdir to $LDFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/lib,
+    dnl   2. if it's already present in $LDFLAGS,
+    dnl   3. if it's /usr/local/lib and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+      haveit=
+      for x in $LDFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-L$additional_libdir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux*) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_libdir"; then
+            dnl Really add $additional_libdir to $LDFLAGS.
+            LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
+          fi
+        fi
+      fi
+    fi
+  fi
+])
+
+dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
+dnl acl_final_exec_prefix, containing the values to which $prefix and
+dnl $exec_prefix will expand at the end of the configure script.
+AC_DEFUN([AC_LIB_PREPARE_PREFIX],
+[
+  dnl Unfortunately, prefix and exec_prefix get only finally determined
+  dnl at the end of configure.
+  if test "X$prefix" = "XNONE"; then
+    acl_final_prefix="$ac_default_prefix"
+  else
+    acl_final_prefix="$prefix"
+  fi
+  if test "X$exec_prefix" = "XNONE"; then
+    acl_final_exec_prefix='${prefix}'
+  else
+    acl_final_exec_prefix="$exec_prefix"
+  fi
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
+dnl variables prefix and exec_prefix bound to the values they will have
+dnl at the end of the configure script.
+AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
+[
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  $1
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_PREPARE_MULTILIB creates
+dnl - a variable acl_libdirstem, containing the basename of the libdir, either
+dnl   "lib" or "lib64" or "lib/64",
+dnl - a variable acl_libdirstem2, as a secondary possible value for
+dnl   acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or
+dnl   "lib/amd64".
+AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
+[
+  dnl There is no formal standard regarding lib and lib64.
+  dnl On glibc systems, the current practice is that on a system supporting
+  dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
+  dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine
+  dnl the compiler's default mode by looking at the compiler's library search
+  dnl path. If at least one of its elements ends in /lib64 or points to a
+  dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI.
+  dnl Otherwise we use the default, namely "lib".
+  dnl On Solaris systems, the current practice is that on a system supporting
+  dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
+  dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or
+  dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib.
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  acl_libdirstem=lib
+  acl_libdirstem2=
+  case "$host_os" in
+    solaris*)
+      dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment
+      dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>.
+      dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link."
+      dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the
+      dnl symlink is missing, so we set acl_libdirstem2 too.
+      AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit],
+        [AC_EGREP_CPP([sixtyfour bits], [
+#ifdef _LP64
+sixtyfour bits
+#endif
+           ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no])
+        ])
+      if test $gl_cv_solaris_64bit = yes; then
+        acl_libdirstem=lib/64
+        case "$host_cpu" in
+          sparc*)        acl_libdirstem2=lib/sparcv9 ;;
+          i*86 | x86_64) acl_libdirstem2=lib/amd64 ;;
+        esac
+      fi
+      ;;
+    *)
+      searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
+      if test -n "$searchpath"; then
+        acl_save_IFS="${IFS= 	}"; IFS=":"
+        for searchdir in $searchpath; do
+          if test -d "$searchdir"; then
+            case "$searchdir" in
+              */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
+              */../ | */.. )
+                # Better ignore directories of this form. They are misleading.
+                ;;
+              *) searchdir=`cd "$searchdir" && pwd`
+                 case "$searchdir" in
+                   */lib64 ) acl_libdirstem=lib64 ;;
+                 esac ;;
+            esac
+          fi
+        done
+        IFS="$acl_save_IFS"
+      fi
+      ;;
+  esac
+  test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
+])
diff --git a/m4/ogg.m4 b/m4/ogg.m4
new file mode 100644
index 0000000..58416ce
--- /dev/null
+++ b/m4/ogg.m4
@@ -0,0 +1,116 @@
+# Configure paths for libogg
+# Jack Moffitt <jack@icecast.org> 10-21-2000
+# Shamelessly stolen from Owen Taylor and Manish Singh
+
+dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS
+dnl
+AC_DEFUN([XIPH_PATH_OGG],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(ogg,AC_HELP_STRING([--with-ogg=PFX],[Prefix where libogg is installed (optional)]), ogg_prefix="$withval", ogg_prefix="")
+AC_ARG_WITH(ogg-libraries,AC_HELP_STRING([--with-ogg-libraries=DIR],[Directory where libogg library is installed (optional)]), ogg_libraries="$withval", ogg_libraries="")
+AC_ARG_WITH(ogg-includes,AC_HELP_STRING([--with-ogg-includes=DIR],[Directory where libogg header files are installed (optional)]), ogg_includes="$withval", ogg_includes="")
+AC_ARG_ENABLE(oggtest,AC_HELP_STRING([--disable-oggtest],[Do not try to compile and run a test Ogg program]),, enable_oggtest=yes)
+
+  if test "x$ogg_libraries" != "x" ; then
+    OGG_LIBS="-L$ogg_libraries"
+  elif test "x$ogg_prefix" = "xno" || test "x$ogg_prefix" = "xyes" ; then
+    OGG_LIBS=""
+  elif test "x$ogg_prefix" != "x" ; then
+    OGG_LIBS="-L$ogg_prefix/lib"
+  elif test "x$prefix" != "xNONE" ; then
+    OGG_LIBS="-L$prefix/lib"
+  fi
+
+  if test "x$ogg_prefix" != "xno" ; then
+    OGG_LIBS="$OGG_LIBS -logg"
+  fi
+
+  if test "x$ogg_includes" != "x" ; then
+    OGG_CFLAGS="-I$ogg_includes"
+  elif test "x$ogg_prefix" = "xno" || test "x$ogg_prefix" = "xyes" ; then
+    OGG_CFLAGS=""
+  elif test "x$ogg_prefix" != "x" ; then
+    OGG_CFLAGS="-I$ogg_prefix/include"
+  elif test "x$prefix" != "xNONE"; then
+    OGG_CFLAGS="-I$prefix/include"
+  fi
+
+  AC_MSG_CHECKING(for Ogg)
+  if test "x$ogg_prefix" = "xno" ; then
+    no_ogg="disabled"
+    enable_oggtest="no"
+  else
+    no_ogg=""
+  fi
+
+
+  if test "x$enable_oggtest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $OGG_CFLAGS"
+    LIBS="$LIBS $OGG_LIBS"
+dnl
+dnl Now check if the installed Ogg is sufficiently new.
+dnl
+      rm -f conf.oggtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ogg/ogg.h>
+
+int main ()
+{
+  system("touch conf.oggtest");
+  return 0;
+}
+
+],, no_ogg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_ogg" = "xdisabled" ; then
+     AC_MSG_RESULT(no)
+     ifelse([$2], , :, [$2])
+  elif test "x$no_ogg" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.oggtest ; then
+       :
+     else
+       echo "*** Could not run Ogg test program, checking why..."
+       CFLAGS="$CFLAGS $OGG_CFLAGS"
+       LIBS="$LIBS $OGG_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <ogg/ogg.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding Ogg or finding the wrong"
+       echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occurred. This usually means Ogg was incorrectly installed"
+       echo "*** or that you have moved Ogg since it was installed." ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     OGG_CFLAGS=""
+     OGG_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(OGG_CFLAGS)
+  AC_SUBST(OGG_LIBS)
+  rm -f conf.oggtest
+])
diff --git a/m4/really_gcc.m4 b/m4/really_gcc.m4
new file mode 100644
index 0000000..cba53ab
--- /dev/null
+++ b/m4/really_gcc.m4
@@ -0,0 +1,32 @@
+dnl @synopsis XIPH_GCC_REALLY_IS_GCC
+dnl
+dnl Find out if a compiler claiming to be gcc really is gcc (clang lies).
+dnl @version 1.0	Oct 31 2013
+dnl @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+dnl
+dnl Permission to use, copy, modify, distribute, and sell this file for any
+dnl purpose is hereby granted without fee, provided that the above copyright
+dnl and this permission notice appear in all copies.  No representations are
+dnl made about the suitability of this software for any purpose.  It is
+dnl provided "as is" without express or implied warranty.
+dnl
+
+# If the configure script has already detected GNU GCC, then make sure it
+# isn't CLANG masquerading as GCC.
+
+AC_DEFUN([XIPH_GCC_REALLY_IS_GCC],
+[	AC_LANG_ASSERT(C)
+	if test "x$ac_cv_c_compiler_gnu" = "xyes" ; then
+		AC_TRY_LINK([
+			#include <stdio.h>
+			],
+			[
+			#ifdef __clang__
+				This is clang!
+			#endif
+			],
+		ac_cv_c_compiler_gnu=yes,
+		ac_cv_c_compiler_gnu=no
+		)
+		fi
+])
diff --git a/m4/stack_protect.m4 b/m4/stack_protect.m4
new file mode 100644
index 0000000..d39f419
--- /dev/null
+++ b/m4/stack_protect.m4
@@ -0,0 +1,73 @@
+dnl Copyright (C) 2013-2016  Xiph.org Foundation
+dnl
+dnl Redistribution and use in source and binary forms, with or without
+dnl modification, are permitted provided that the following conditions
+dnl are met:
+dnl
+dnl - Redistributions of source code must retain the above copyright
+dnl notice, this list of conditions and the following disclaimer.
+dnl
+dnl - Redistributions in binary form must reproduce the above copyright
+dnl notice, this list of conditions and the following disclaimer in the
+dnl documentation and/or other materials provided with the distribution.
+dnl
+dnl - Neither the name of the Xiph.org Foundation nor the names of its
+dnl contributors may be used to endorse or promote products derived from
+dnl this software without specific prior written permission.
+dnl
+dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+dnl ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+dnl A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+dnl CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+dnl PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+dnl LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+dnl NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+dnl SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+dnl We want to know if GCC stack protector works, for the C and for the C++
+dnl compiler.
+dnl
+dnl Just checking if the compiler accepts the required CFLAGSs is not enough
+dnl because we have seen at least one instance where this check was
+dnl in-sufficient.
+dnl
+dnl Instead, try to compile and link a test program with the stack protector
+dnl flags. If that works, we use it.
+
+AC_DEFUN([XIPH_GCC_STACK_PROTECTOR],
+[AC_LANG_ASSERT(C)
+	AC_MSG_CHECKING([if $CC supports stack smash protection])
+	xiph_stack_check_old_cflags="$CFLAGS"
+	SSP_FLAGS="-fstack-protector-strong"
+	CFLAGS=$SSP_FLAGS
+	AC_TRY_LINK([
+			#include <stdio.h>
+			],
+		[puts("Hello, World!"); return 0;],
+		AC_MSG_RESULT([yes])
+			CFLAGS="$xiph_stack_check_old_cflags $SSP_FLAGS",
+		AC_MSG_RESULT([no])
+			CFLAGS="$xiph_stack_check_old_cflags"
+		)
+])# XIPH_GCC_STACK_PROTECTOR
+
+AC_DEFUN([XIPH_GXX_STACK_PROTECTOR],
+[AC_LANG_PUSH([C++])
+	AC_MSG_CHECKING([if $CXX supports stack smash protection])
+	xiph_stack_check_old_cflags="$CFLAGS"
+	SSP_FLAGS="-fstack-protector-strong"
+	CFLAGS=$SSP_FLAGS
+	AC_TRY_LINK([
+			#include <cstdio>
+			],
+		[puts("Hello, World!"); return 0;],
+		AC_MSG_RESULT([yes])
+			CFLAGS="$xiph_stack_check_old_cflags $SSP_FLAGS",
+		AC_MSG_RESULT([no])
+			CFLAGS="$xiph_stack_check_old_cflags"
+		)
+	AC_LANG_POP([C++])
+])# XIPH_GXX_STACK_PROTECTOR
diff --git a/m4/xmms.m4 b/m4/xmms.m4
new file mode 100644
index 0000000..d172095
--- /dev/null
+++ b/m4/xmms.m4
@@ -0,0 +1,148 @@
+# CFLAGS and library paths for XMMS
+# written 15 December 1999 by Ben Gertzfield <che@debian.org>
+
+dnl Usage:
+dnl AM_PATH_XMMS([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl
+dnl Example:
+dnl AM_PATH_XMMS(0.9.5.1, , AC_MSG_ERROR([*** XMMS >= 0.9.5.1 not installed - please install first ***]))
+dnl
+dnl Defines XMMS_CFLAGS, XMMS_LIBS, XMMS_DATA_DIR, XMMS_PLUGIN_DIR, 
+dnl XMMS_VISUALIZATION_PLUGIN_DIR, XMMS_INPUT_PLUGIN_DIR, 
+dnl XMMS_OUTPUT_PLUGIN_DIR, XMMS_GENERAL_PLUGIN_DIR, XMMS_EFFECT_PLUGIN_DIR,
+dnl and XMMS_VERSION for your plugin pleasure.
+dnl
+
+dnl XMMS_TEST_VERSION(AVAILABLE-VERSION, NEEDED-VERSION [, ACTION-IF-OKAY [, ACTION-IF-NOT-OKAY]])
+AC_DEFUN([XMMS_TEST_VERSION], [
+
+# Determine which version number is greater. Prints 2 to stdout if	
+# the second number is greater, 1 if the first number is greater,	
+# 0 if the numbers are equal.						
+									
+# Written 15 December 1999 by Ben Gertzfield <che@debian.org>		
+# Revised 15 December 1999 by Jim Monty <monty@primenet.com>		
+									
+    AC_PROG_AWK
+    xmms_got_version=[` $AWK '						\
+BEGIN {									\
+    print vercmp(ARGV[1], ARGV[2]);					\
+}									\
+									\
+function vercmp(ver1, ver2,    ver1arr, ver2arr,			\
+                               ver1len, ver2len,			\
+                               ver1int, ver2int, len, i, p) {		\
+									\
+    ver1len = split(ver1, ver1arr, /\./);				\
+    ver2len = split(ver2, ver2arr, /\./);				\
+									\
+    len = ver1len > ver2len ? ver1len : ver2len;			\
+									\
+    for (i = 1; i <= len; i++) {					\
+        p = 1000 ^ (len - i);						\
+        ver1int += ver1arr[i] * p;					\
+        ver2int += ver2arr[i] * p;					\
+    }									\
+									\
+    if (ver1int < ver2int)						\
+        return 2;							\
+    else if (ver1int > ver2int)						\
+        return 1;							\
+    else								\
+        return 0;							\
+}' $1 $2`]								
+
+    if test $xmms_got_version -eq 2; then 	# failure
+	ifelse([$4], , :, $4)			
+    else  					# success!
+	ifelse([$3], , :, $3)
+    fi
+])
+
+AC_DEFUN([AM_PATH_XMMS],
+[
+AC_ARG_WITH(xmms-prefix,[  --with-xmms-prefix=PFX  Prefix where XMMS is installed (optional)],
+	xmms_config_prefix="$withval", xmms_config_prefix="")
+AC_ARG_WITH(xmms-exec-prefix,[  --with-xmms-exec-prefix=PFX Exec prefix where XMMS is installed (optional)],
+	xmms_config_exec_prefix="$withval", xmms_config_exec_prefix="")
+
+if test x$xmms_config_exec_prefix != x; then
+    xmms_config_args="$xmms_config_args --exec-prefix=$xmms_config_exec_prefix"
+    if test x${XMMS_CONFIG+set} != xset; then
+	XMMS_CONFIG=$xmms_config_exec_prefix/bin/xmms-config
+    fi
+fi
+
+if test x$xmms_config_prefix != x; then
+    xmms_config_args="$xmms_config_args --prefix=$xmms_config_prefix"
+    if test x${XMMS_CONFIG+set} != xset; then
+  	XMMS_CONFIG=$xmms_config_prefix/bin/xmms-config
+    fi
+fi
+
+AC_PATH_PROG(XMMS_CONFIG, xmms-config, no)
+min_xmms_version=ifelse([$1], ,0.9.5.1, $1)
+
+if test "$XMMS_CONFIG" = "no"; then
+    no_xmms=yes
+else
+    XMMS_CFLAGS=`$XMMS_CONFIG $xmms_config_args --cflags`
+    XMMS_LIBS=`$XMMS_CONFIG $xmms_config_args --libs`
+    XMMS_VERSION=`$XMMS_CONFIG $xmms_config_args --version`
+    XMMS_DATA_DIR=`$XMMS_CONFIG $xmms_config_args --data-dir`
+    XMMS_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --plugin-dir`
+    XMMS_VISUALIZATION_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args \
+					--visualization-plugin-dir`
+    XMMS_INPUT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --input-plugin-dir`
+    XMMS_OUTPUT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --output-plugin-dir`
+    XMMS_EFFECT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --effect-plugin-dir`
+    XMMS_GENERAL_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --general-plugin-dir`
+
+    XMMS_TEST_VERSION($XMMS_VERSION, $min_xmms_version, ,no_xmms=version)
+fi
+
+AC_MSG_CHECKING(for XMMS - version >= $min_xmms_version)
+
+if test "x$no_xmms" = x; then
+    AC_MSG_RESULT(yes)
+    ifelse([$2], , :, [$2])
+else
+    AC_MSG_RESULT(no)
+
+    if test "$XMMS_CONFIG" = "no" ; then
+	echo "*** The xmms-config script installed by XMMS could not be found."
+      	echo "*** If XMMS was installed in PREFIX, make sure PREFIX/bin is in"
+	echo "*** your path, or set the XMMS_CONFIG environment variable to the"
+	echo "*** full path to xmms-config."
+    else
+	if test "$no_xmms" = "version"; then
+	    echo "*** An old version of XMMS, $XMMS_VERSION, was found."
+	    echo "*** You need a version of XMMS newer than $min_xmms_version."
+	    echo "*** The latest version of XMMS is always available from"
+	    echo "*** http://www.xmms.org/"
+	    echo "***"
+
+            echo "*** If you have already installed a sufficiently new version, this error"
+            echo "*** probably means that the wrong copy of the xmms-config shell script is"
+            echo "*** being found. The easiest way to fix this is to remove the old version"
+            echo "*** of XMMS, but you can also set the XMMS_CONFIG environment to point to the"
+            echo "*** correct copy of xmms-config. (In this case, you will have to"
+            echo "*** modify your LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf"
+            echo "*** so that the correct libraries are found at run-time)"
+	fi
+    fi
+    XMMS_CFLAGS=""
+    XMMS_LIBS=""
+    ifelse([$3], , :, [$3])
+fi
+AC_SUBST(XMMS_CFLAGS)
+AC_SUBST(XMMS_LIBS)
+AC_SUBST(XMMS_VERSION)
+AC_SUBST(XMMS_DATA_DIR)
+AC_SUBST(XMMS_PLUGIN_DIR)
+AC_SUBST(XMMS_VISUALIZATION_PLUGIN_DIR)
+AC_SUBST(XMMS_INPUT_PLUGIN_DIR)
+AC_SUBST(XMMS_OUTPUT_PLUGIN_DIR)
+AC_SUBST(XMMS_GENERAL_PLUGIN_DIR)
+AC_SUBST(XMMS_EFFECT_PLUGIN_DIR)
+])
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..fe9f0bc
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,38 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+if FLaC__HAS_DOCBOOK_TO_MAN
+flac.1: flac.sgml
+	docbook-to-man $? > $@
+	(docbook2man $? && mv FLAC.1 $@)
+
+metaflac.1: metaflac.sgml
+	docbook-to-man $? > $@
+	(docbook2man $? && mv METAFLAC.1 $@)
+else
+flac.1:
+	echo "*** Warning: docbook-to-man not found; man pages will not be built."
+	touch $@
+
+metaflac.1:
+	touch $@
+endif
+
+man_MANS = flac.1 metaflac.1
+
+EXTRA_DIST = $(man_MANS) flac.sgml metaflac.sgml
diff --git a/man/flac.1 b/man/flac.1
new file mode 100644
index 0000000..853b89c
--- /dev/null
+++ b/man/flac.1
@@ -0,0 +1,390 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "FLAC" "1" "2013/09/18" "" ""
+
+.SH NAME
+flac \- Free Lossless Audio Codec
+.SH SYNOPSIS
+
+\fBflac\fR [ \fB\fIOPTIONS\fB\fR ] [ \fB\fIinfile.wav\fB\fR | \fB\fIinfile.rf64\fB\fR | \fB\fIinfile.aiff\fB\fR | \fB\fIinfile.raw\fB\fR | \fB\fIinfile.flac\fB\fR | \fB\fIinfile.oga\fB\fR | \fB\fIinfile.ogg\fB\fR | \fB-\fR\fI ...\fR ]
+
+
+\fBflac\fR [ \fB-d\fR | \fB--decode\fR | \fB-t\fR | \fB--test\fR | \fB-a\fR | \fB--analyze\fR ] [ \fB\fIOPTIONS\fB\fR ] [ \fB\fIinfile.flac\fB\fR | \fB\fIinfile.oga\fB\fR | \fB\fIinfile.ogg\fB\fR | \fB-\fR\fI ...\fR ]
+
+.SH "DESCRIPTION"
+.PP
+\fBflac\fR is a command-line tool for encoding, decoding, testing and analyzing FLAC streams.
+.SH "OPTIONS"
+.PP
+A summary of options is included below.  For a complete
+description, see the HTML documentation.
+.SS "GENERAL OPTIONS"
+.TP
+\fB-v, --version\fR
+Show the flac version number
+.TP
+\fB-h, --help \fR
+Show basic usage and a list of all options
+.TP
+\fB-H, --explain \fR
+Show detailed explanation of usage and all options
+.TP
+\fB-d, --decode \fR
+Decode (the default behavior is to encode)
+.TP
+\fB-t, --test \fR
+Test a flac encoded file (same as -d except no decoded file is written)
+.TP
+\fB-a, --analyze \fR
+Analyze a FLAC encoded file (same as -d except an analysis file is written)
+.TP
+\fB-c, --stdout \fR
+Write output to stdout
+.TP
+\fB-s, --silent \fR
+Silent mode (do not write runtime encode/decode statistics to stderr)
+.TP
+\fB--totally-silent \fR
+Do not print anything of any kind, including warnings or errors.  The exit code will be the only way to determine successful completion.
+.TP
+\fB--no-utf8-convert \fR
+Do not convert tags from local charset to UTF-8.  This is useful for scripts, and setting tags in situations where the locale is wrong.  This option must appear before any tag options!
+.TP
+\fB-w, --warnings-as-errors \fR
+Treat all warnings as errors (which cause flac to terminate with a non-zero exit code).
+.TP
+\fB-f, --force \fR
+Force overwriting of output files.  By default, flac warns that the output file already exists and continues to the next file.
+.TP
+\fB-o \fIfilename\fB, --output-name=\fIfilename\fB\fR
+Force the output file name (usually flac just changes the extension).  May only be used when encoding a single file.  May not be used in conjunction with --output-prefix.
+.TP
+\fB--output-prefix=\fIstring\fB\fR
+Prefix each output file name with the given string.  This can be useful for encoding or decoding files to a different directory.  Make sure if your string is a path name that it ends with a trailing `/' (slash).
+.TP
+\fB--delete-input-file \fR
+Automatically delete the input file after a successful encode or decode.  If there was an error (including a verify error) the input file is left intact.
+.TP
+\fB--preserve-modtime \fR
+Output files have their timestamps/permissions set to match those of their inputs (this is default).  Use --no-preserve-modtime to make output files have the current time and default permissions.
+.TP
+\fB--keep-foreign-metadata \fR
+If encoding, save WAVE, RF64, or AIFF non-audio chunks in FLAC metadata.  If decoding, restore any saved non-audio chunks from FLAC metadata when writing the decoded file.  Foreign metadata cannot be transcoded, e.g. WAVE chunks saved in a FLAC file cannot be restored when decoding to AIFF.  Input and output must be regular files (not stdin or stdout).
+.TP
+\fB--skip={\fI#\fB|\fImm:ss.ss\fB}\fR
+Skip over the first number of samples of the input.  This works for both encoding and decoding, but not testing.  The alternative form mm:ss.ss can be used to specify minutes, seconds, and fractions of a second.
+.TP
+\fB--until={\fI#\fB|[\fI+\fB|\fI-\fB]\fImm:ss.ss\fB}\fR
+Stop at the given sample number for each input file.  This works for both encoding and decoding, but not testing.  The given sample number is not included in the decoded output.  The alternative form mm:ss.ss can be used to specify minutes, seconds, and fractions of a second.  If a `+' (plus) sign is at the beginning, the --until point is relative to the --skip point.  If a `-' (minus) sign is at the beginning, the --until point is relative to end of the audio.
+.TP
+\fB--ogg\fR
+When encoding, generate Ogg FLAC output instead of native FLAC.  Ogg FLAC streams are FLAC streams wrapped in an Ogg transport layer.  The resulting file should have an '.oga' extension and will still be decodable by flac.
+
+When decoding, force the input to be treated as Ogg FLAC.  This is useful when piping input from stdin or when the filename does not end in '.oga' or '.ogg'.
+.TP
+\fB--serial-number=\fI#\fB\fR
+When used with --ogg, specifies the serial number to use for the first Ogg FLAC stream, which is then incremented for each additional stream.  When encoding and no serial number is given, flac uses a random number for the first stream, then increments it for each additional stream.  When decoding and no number is given, flac uses the serial number of the first page.
+.SS "ANALYSIS OPTIONS"
+.TP
+\fB--residual-text \fR
+Includes the residual signal in the analysis file.  This will make the file very big, much larger than even the decoded file.
+.TP
+\fB--residual-gnuplot \fR
+Generates a gnuplot file for every subframe; each file will contain the residual distribution of the subframe.  This will create a lot of files.
+.SS "DECODING OPTIONS"
+.TP
+\fB--cue=[\fI#.#\fB][-[\fI#.#\fB]]\fR
+Set the beginning and ending cuepoints to decode.  The optional first #.# is the track and index point at which decoding will start; the default is the beginning of the stream.  The optional second #.# is the track and index point at which decoding will end; the default is the end of the stream.  If the cuepoint does not exist, the closest one before it (for the start point) or after it (for the end point) will be used.  If those don't exist, the start of the stream (for the start point) or end of the stream (for the end point) will be used.  The cuepoints are merely translated into sample numbers then used as --skip and --until.  A CD track can always be cued by, for example, --cue=9.1-10.1 for track 9, even if the CD has no 10th track.
+.TP
+\fB-F, --decode-through-errors \fR
+By default flac stops decoding with an error and removes the partially decoded file if it encounters a bitstream error.  With -F, errors are still printed but flac will continue decoding to completion.  Note that errors may cause the decoded audio to be missing some samples or have silent sections.
+.TP
+\fB--apply-replaygain-which-is-not-lossless[=<specification>] \fR
+Applies ReplayGain values while decoding.
+
+WARNING: THIS IS NOT LOSSLESS.  DECODED AUDIO WILL NOT BE IDENTICAL TO THE ORIGINAL WITH THIS OPTION.
+
+The equals sign and <specification> is optional.  If omitted, the default is 0aLn1.
+
+The <specification> is a shorthand notation for describing how to apply ReplayGain.  All components are optional but order is important.  '[]' means 'optional'.  '|' means 'or'.  '{}' means required.  The format is:
+
+[<preamp>][a|t][l|L][n{0|1|2|3}]
+.RS
+.TP
+\fBpreamp\fR
+A floating point number in dB.  This is added to the existing gain value.
+.TP
+\fBa|t\fR
+Specify 'a' to use the album gain, or 't' to use the track gain.  If tags for the preferred kind (album/track) do not exist but tags for the other (track/album) do, those will be used instead.
+.TP
+\fBl|L\fR
+Specify 'l' to peak-limit the output, so that the ReplayGain peak value is full-scale.  Specify 'L' to use a 6dB hard limiter that kicks in when the signal approaches full-scale.
+.TP
+\fBn{0|1|2|3}\fR
+Specify the amount of noise shaping.  ReplayGain synthesis happens in floating point; the result is dithered before converting back to integer.  This quantization adds noise.  Noise shaping tries to move the noise where you won't hear it as much.  0 means no noise shaping, 1 means 'low', 2 means 'medium', 3 means 'high'.
+.RE
+
+For example, the default of 0aLn1 means 0dB preamp, use album gain, 6dB hard limit, low noise shaping.
+
+--apply-replaygain-which-is-not-lossless=3 means 3dB preamp, use album gain, no limiting, no noise shaping.
+
+flac uses the ReplayGain tags for the calculation.  If a stream does not have the required tags or they can't be parsed, decoding will continue with a warning, and no ReplayGain is applied to that stream.
+.SS "ENCODING OPTIONS"
+.TP
+\fB-V, --verify\fR
+Verify a correct encoding by decoding the output in parallel and comparing to the original
+.TP
+\fB--lax\fR
+Allow encoder to generate non-Subset files.  The resulting FLAC file may not be streamable or might have trouble being played in all players (especially hardware devices), so you should only use this option in combination with custom encoding options meant for archival.
+.TP
+\fB--replay-gain\fR
+Calculate ReplayGain values and store them as FLAC tags, similar to vorbisgain.  Title gains/peaks will be computed for each input file, and an album gain/peak will be computed for all files.  All input files must have the same resolution, sample rate, and number of channels.  Only mono and stereo files are allowed, and the sample rate must be one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, or 48 kHz.  Also note that this option may leave a few extra bytes in a PADDING block as the exact size of the tags is not known until all files are processed.  Note that this option cannot be used when encoding to standard output (stdout).
+.TP
+\fB--cuesheet=\fIfilename\fB\fR
+Import the given cuesheet file and store it in a CUESHEET metadata block.  This option may only be used when encoding a single file.  A seekpoint will be added for each index point in the cuesheet to the SEEKTABLE unless --no-cued-seekpoints is specified.
+.TP
+\fB--picture={\fIFILENAME\fB|\fISPECIFICATION\fB}\fR
+Import a picture and store it in a PICTURE metadata block.  More than one --picture command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The SPECIFICATION is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  FILENAME is just shorthand for "||||FILENAME".  The format of SPECIFICATION is
+
+[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE
+
+TYPE is optional; it is a number from one of:
+
+0: Other
+
+1: 32x32 pixels 'file icon' (PNG only)
+
+2: Other file icon
+
+3: Cover (front)
+
+4: Cover (back)
+
+5: Leaflet page
+
+6: Media (e.g. label side of CD)
+
+7: Lead artist/lead performer/soloist
+
+8: Artist/performer
+
+9: Conductor
+
+10: Band/Orchestra
+
+11: Composer
+
+12: Lyricist/text writer
+
+13: Recording Location
+
+14: During recording
+
+15: During performance
+
+16: Movie/video screen capture
+
+17: A bright coloured fish
+
+18: Illustration
+
+19: Band/artist logotype
+
+20: Publisher/Studio logotype
+
+The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.
+
+MIME-TYPE is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type image/jpeg or image/png.  The MIME type can also be --> to mean that FILE is actually a URL to an image, though this use is discouraged.
+
+DESCRIPTION is optional; the default is an empty string.
+
+The next part specifies the resolution and color information.  If the MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.
+
+FILE is the path to the picture file to be imported, or the URL if MIME type is -->
+
+For example, "|image/jpeg|||../cover.jpg" will embed the JPEG file at ../cover.jpg, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.
+
+The specification "4|-->|CD|320x300x24/173|http://blah.blah/backcover.tiff" will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.
+.TP
+\fB--sector-align\fR
+Align encoding of multiple CD format files on sector boundaries.  See the HTML documentation for more information.  This option is DEPRECATED and may not exist in future versions of flac.
+.TP
+\fB--ignore-chunk-sizes\fR
+When encoding to flac, ignore the file size headers in WAV and AIFF files to attempt to work around problems with over-sized or malformed files.
+
+WAV and AIFF files both have an unsigned 32 bit numbers in the file header which specifes the length of audio data. Since this number is unsigned 32 bits, that limits the size of a valid file to being just over 4 Gigabytes. Files larger than this are mal-formed, but should be read correctly using this option.
+.TP
+\fB-S {\fI#\fB|\fIX\fB|\fI#x\fB|\fI#s\fB}, --seekpoint={\fI#\fB|\fIX\fB|\fI#x\fB|\fI#s\fB}\fR
+Include a point or points in a SEEKTABLE.  Using #, a seek point at that sample number is added.  Using X, a placeholder point is added at the end of a the table.  Using #x, # evenly spaced seek points will be added, the first being at sample 0.  Using #s, a seekpoint will be added every # seconds (# does not have to be a whole number; it can be, for example, 9.5, meaning a seekpoint every 9.5 seconds).  You may use many -S options; the resulting SEEKTABLE will be the unique-ified union of all such values.  With no -S options, flac defaults to '-S 10s'.  Use --no-seektable for no SEEKTABLE.  Note: '-S #x' and '-S #s' will not work if the encoder can't determine the input size before starting.  Note: if you use '-S #' and # is >= samples in the input, there will be either no seek point entered (if the input size is determinable before encoding starts) or a placeholder point (if input size is not determinable).
+.TP
+\fB-P \fI#\fB, --padding=\fI#\fB\fR
+Tell the encoder to write a PADDING metadata block of the given length (in bytes) after the STREAMINFO block.  This is useful if you plan to tag the file later with an APPLICATION block; instead of having to rewrite the entire file later just to insert your block, you can write directly over the PADDING block.  Note that the total length of the PADDING block will be 4 bytes longer than the length given because of the 4 metadata block header bytes.  You can force no PADDING block at all to be written with --no-padding.  The encoder writes a PADDING block of 8192 bytes by default (or 65536 bytes if the input audio stream is more that 20 minutes long).
+.TP
+\fB-T \fIFIELD=VALUE\fB, --tag=\fIFIELD=VALUE\fB\fR
+Add a FLAC tag.  The comment must adhere to the Vorbis comment spec; i.e. the FIELD must contain only legal characters, terminated by an 'equals' sign.  Make sure to quote the comment if necessary.  This option may appear more than once to add several comments.  NOTE: all tags will be added to all encoded files.
+.TP
+\fB--tag-from-file=\fIFIELD=FILENAME\fB\fR
+Like --tag, except FILENAME is a file whose contents will be read verbatim to set the tag value.  The contents will be converted to UTF-8 from the local charset.  This can be used to store a cuesheet in a tag (e.g.  --tag-from-file="CUESHEET=image.cue").  Do not try to store binary data in tag fields!  Use APPLICATION blocks for that.
+.TP
+\fB-b \fI#\fB, --blocksize=\fI#\fB\fR
+Specify the block size in samples.  Subset streams must use one of 192, 576, 1152, 2304, 4608, 256, 512, 1024, 2048, 4096 (and 8192 or 16384 if the sample rate is >48kHz).
+.TP
+\fB-m, --mid-side\fR
+Try mid-side coding for each frame (stereo input only)
+.TP
+\fB-M, --adaptive-mid-side\fR
+Adaptive mid-side coding for all frames (stereo input only)
+.TP
+\fB-0\&..-8, --compression-level-0\&..--compression-level-8\fR
+Fastest compression..highest compression (default is -5).  These are synonyms for other options:
+.RS
+.TP
+\fB-0, --compression-level-0\fR
+Synonymous with -l 0 -b 1152 -r 3 --no-mid-side
+.TP
+\fB-1, --compression-level-1\fR
+Synonymous with -l 0 -b 1152 -M -r 3
+.TP
+\fB-2, --compression-level-2\fR
+Synonymous with -l 0 -b 1152 -m -r 3
+.TP
+\fB-3, --compression-level-3\fR
+Synonymous with -l 6 -b 4096 -r 4 --no-mid-side
+.TP
+\fB-4, --compression-level-4\fR
+Synonymous with -l 8 -b 4096 -M -r 4
+.TP
+\fB-5, --compression-level-5\fR
+Synonymous with -l 8 -b 4096 -m -r 5
+.TP
+\fB-6, --compression-level-6\fR
+Synonymous with -l 8 -b 4096 -m -r 6 -A tukey(0.5) -A partial_tukey(2)
+.TP
+\fB-7, --compression-level-7\fR
+Synonymous with -l 12 -b 4096 -m -r 6 -A tukey(0.5) -A partial_tukey(2)
+.TP
+\fB-8, --compression-level-8\fR
+Synonymous with -l 12 -b 4096 -m -r 6 -A tukey(0.5) -A partial_tukey(2) -A punchout_tukey(3)
+.RE
+.TP
+\fB--fast\fR
+Fastest compression.  Currently synonymous with -0.
+.TP
+\fB--best\fR
+Highest compression.  Currently synonymous with -8.
+.TP
+\fB-e, --exhaustive-model-search\fR
+Do exhaustive model search (expensive!)
+.TP
+\fB-A \fIfunction\fB, --apodization=\fIfunction\fB\fR
+Window audio data with given the apodization function.  The functions are: bartlett, bartlett_hann, blackman, blackman_harris_4term_92db, connes, flattop, gauss(STDDEV), hamming, hann, kaiser_bessel, nuttall, rectangle, triangle, tukey(P), partial_tukey(n[/ov[/P]]), punchout_tukey(n[/ov[/P]]), welch.
+
+For gauss(STDDEV), STDDEV is the standard deviation (0<STDDEV<=0.5).
+
+For tukey(P), P specifies the fraction of the window that is tapered (0<=P<=1; P=0 corresponds to "rectangle" and P=1 corresponds to "hann").
+
+For partial_tukey(n) and punchout_tukey(n), n apodization functions are added that span different parts of each block. Values of 2 to 6 seem to yield sane results. If necessary, an overlap can be specified, as can be the taper parameter, for example partial_tukey(2/0.2) or partial_tukey(2/0.2/0.5). ov should be smaller than 1 and can be negative.
+
+Please note that P, STDDEV and ov are locale specific, so a comma as decimal separator might be required instead of a dot.
+
+More than one -A option (up to 32) may be used.  Any function that is specified erroneously is silently dropped.  The encoder chooses suitable defaults in the absence of any -A options; any -A option specified replaces the default(s).
+
+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.  Multiple functions can greatly increase the encoding time.
+.TP
+\fB-l \fI#\fB, --max-lpc-order=\fI#\fB\fR
+Specifies the maximum LPC order. This number must be <= 32. For Subset streams, it must be <=12 if the sample rate is <=48kHz. If 0, the encoder will not attempt generic linear prediction, and use only fixed predictors. Using fixed predictors is faster but usually results in files being 5-10% larger.
+.TP
+\fB-p, --qlp-coeff-precision-search\fR
+Do exhaustive search of LP coefficient quantization (expensive!).  Overrides -q; does nothing if using -l 0
+.TP
+\fB-q \fI#\fB, --qlp-coeff-precision=\fI#\fB\fR
+Precision of the quantized linear-predictor coefficients, 0 => let encoder decide (min is 5, default is 0)
+.TP
+\fB-r [\fI#\fB,]\fI#\fB, --rice-partition-order=[\fI#\fB,]\fI#\fB\fR
+Set the [min,]max residual partition order (0..15). min defaults to 0 if unspecified.  Default is -r 5.
+.SS "FORMAT OPTIONS"
+.TP
+\fB--endian={\fIbig\fB|\fIlittle\fB}\fR
+Set the byte order for samples
+.TP
+\fB--channels=\fI#\fB\fR
+Set number of channels.
+.TP
+\fB--bps=\fI#\fB\fR
+Set bits per sample.
+.TP
+\fB--sample-rate=\fI#\fB\fR
+Set sample rate (in Hz).
+.TP
+\fB--sign={\fIsigned\fB|\fIunsigned\fB}\fR
+Set the sign of samples (the default is signed).
+.TP
+\fB--input-size=\fI#\fB\fR
+Specify the size of the raw input in bytes.  If you are encoding raw samples from stdin, you must set this option in order to be able to use --skip, --until, --cuesheet, or other options that need to know the size of the input beforehand.  If the size given is greater than what is found in the input stream, the encoder will complain about an unexpected end-of-file.  If the size given is less, samples will be truncated.
+.TP
+\fB--force-raw-format\fR
+Force input (when encoding) or output (when decoding) to be treated as raw samples (even if filename ends in \fI\&.wav\fR).
+.TP
+\fB--force-aiff-format\fR
+Force the decoder to output AIFF format.  This option is not needed if the output filename (as set by -o) ends with \fI\&.aif\fR or \fI\&.aiff\fR\&.  Also, this option has no effect when encoding since input AIFF is auto-detected.
+.TP
+\fB--force-rf64-format\fR
+Force the decoder to output RF64 format.  This option is not needed if the output filename (as set by -o) ends with \fI\&.rf64\fR\&.  Also, this option has no effect when encoding since input RF64 is auto-detected.
+.TP
+\fB--force-wave64-format\fR
+Force the decoder to output Wave64 format.  This option is not needed if the output filename (as set by -o) ends with \fI\&.w64\fR\&.  Also, this option has no effect when encoding since input Wave64 is auto-detected.
+.SS "NEGATIVE OPTIONS"
+.TP
+\fB--no-adaptive-mid-side\fR
+.TP
+\fB--no-cued-seekpoints\fR
+.TP
+\fB--no-decode-through-errors\fR
+.TP
+\fB--no-delete-input-file\fR
+.TP
+\fB--no-preserve-modtime\fR
+.TP
+\fB--no-keep-foreign-metadata\fR
+.TP
+\fB--no-exhaustive-model-search\fR
+.TP
+\fB--no-force\fR
+.TP
+\fB--no-lax\fR
+.TP
+\fB--no-mid-side\fR
+.TP
+\fB--no-ogg\fR
+.TP
+\fB--no-padding\fR
+.TP
+\fB--no-qlp-coeff-prec-search\fR
+.TP
+\fB--no-replay-gain\fR
+.TP
+\fB--no-residual-gnuplot\fR
+.TP
+\fB--no-residual-text\fR
+.TP
+\fB--no-sector-align\fR
+.TP
+\fB--no-seektable\fR
+.TP
+\fB--no-silent\fR
+.TP
+\fB--no-verify\fR
+.TP
+\fB--no-warnings-as-errors\fR
+These flags can be used to invert the sense of the corresponding normal option.
+.SH "SEE ALSO"
+.PP
+metaflac(1)
+.PP
+The programs are documented fully by HTML format documentation, available in \fI/usr/share/doc/libflac-doc/html\fR on Debian GNU/Linux systems.
+.SH "AUTHOR"
+.PP
+This manual page was initially written by Matt Zimmerman <mdz@debian.org> for the Debian GNU/Linux system (but may be used by others). It has been kept up-to-date by the Xiph.org Foundation.
diff --git a/man/flac.sgml b/man/flac.sgml
new file mode 100644
index 0000000..87a3f23
--- /dev/null
+++ b/man/flac.sgml
@@ -0,0 +1,814 @@
+<!doctype refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
+
+  <!-- Fill in your name for FIRSTNAME and SURNAME. -->
+  <!ENTITY dhfirstname "<firstname>Matt</firstname>">
+  <!ENTITY dhsurname   "<surname>Zimmerman</surname>">
+  <!-- Please adjust the date whenever revising the manpage. -->
+  <!ENTITY dhdate      "<date>2013/09/18</date>">
+  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
+       allowed: see man(7), man(1). -->
+  <!ENTITY dhsection   "<manvolnum>1</manvolnum>">
+  <!ENTITY dhemail     "<email>mdz@debian.org</email>">
+  <!ENTITY dhusername  "Matt Zimmerman">
+  <!ENTITY dhucpackage "<refentrytitle>FLAC</refentrytitle>">
+  <!ENTITY dhpackage   "flac">
+
+  <!ENTITY debian      "<productname>Debian GNU/Linux</productname>">
+  <!ENTITY gnu         "<acronym>GNU</acronym>">
+]>
+
+<refentry>
+  <docinfo>
+    <address>
+      &dhemail;
+    </address>
+    <author>
+      &dhfirstname;
+      &dhsurname;
+    </author>
+    <copyright>
+      <year>2002-2005, 2011-2013</year>
+      <holder>&dhusername;</holder>
+    </copyright>
+    &dhdate;
+  </docinfo>
+  <refmeta>
+    &dhucpackage;
+
+    &dhsection;
+  </refmeta>
+  <refnamediv>
+    <refname>&dhpackage;</refname>
+
+    <refpurpose>Free Lossless Audio Codec</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>flac</command>
+      <arg choice=opt><replaceable>OPTIONS</replaceable></arg>
+      <group rep=repeat>
+	<arg><replaceable>infile.wav</replaceable></arg>
+	<arg><replaceable>infile.rf64</replaceable></arg>
+	<arg><replaceable>infile.aiff</replaceable></arg>
+	<arg><replaceable>infile.raw</replaceable></arg>
+	<arg><replaceable>infile.flac</replaceable></arg>
+	<arg><replaceable>infile.oga</replaceable></arg>
+	<arg><replaceable>infile.ogg</replaceable></arg>
+	<arg>-</arg>
+      </group>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>flac</command>
+      <group>
+	<arg>-d</arg> <arg>--decode</arg>
+	<arg>-t</arg> <arg>--test</arg>
+	<arg>-a</arg> <arg>--analyze</arg>
+      </group>
+      <arg choice=opt><replaceable>OPTIONS</replaceable></arg>
+      <group rep=repeat>
+	<arg><replaceable>infile.flac</replaceable></arg>
+	<arg><replaceable>infile.oga</replaceable></arg>
+	<arg><replaceable>infile.ogg</replaceable></arg>
+	<arg>-</arg>
+      </group>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para><command>flac</command> is a command-line tool for encoding, decoding, testing and analyzing FLAC streams.</para>
+
+  </refsect1>
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <para>A summary of options is included below.  For a complete
+    description, see the HTML documentation.</para>
+
+    <refsect2>
+      <title>General Options</title>
+
+      <variablelist>
+	<varlistentry>
+	  <term><option>-v</option>, <option>--version</option></term>
+	  <listitem>
+	    <para>Show the flac version number</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-h</option>, <option>--help</option>
+	  </term>
+	  <listitem>
+	    <para>Show basic usage and a list of all options</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-H</option>, <option>--explain</option>
+	  </term>
+	  <listitem>
+	    <para>Show detailed explanation of usage and all options</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-d</option>, <option>--decode</option>
+	  </term>
+	  <listitem>
+	    <para>Decode (the default behavior is to encode)</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-t</option>, <option>--test</option>
+	  </term>
+	  <listitem>
+	    <para>Test a flac encoded file (same as -d except no decoded file is written)</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-a</option>, <option>--analyze</option>
+	  </term>
+	  <listitem>
+	    <para>Analyze a FLAC encoded file (same as -d except an analysis file is written)</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-c</option>, <option>--stdout</option>
+	  </term>
+	  <listitem>
+	    <para>Write output to stdout</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-s</option>, <option>--silent</option>
+	  </term>
+	  <listitem>
+	    <para>Silent mode (do not write runtime encode/decode statistics to stderr)</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--totally-silent</option>
+	  </term>
+	  <listitem>
+	    <para>Do not print anything of any kind, including warnings or errors.  The exit code will be the only way to determine successful completion.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--no-utf8-convert</option>
+	  </term>
+	  <listitem>
+	    <para>Do not convert tags from local charset to UTF-8.  This is useful for scripts, and setting tags in situations where the locale is wrong.  This option must appear before any tag options!</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-w</option>, <option>--warnings-as-errors</option>
+	  </term>
+	  <listitem>
+	    <para>Treat all warnings as errors (which cause flac to terminate with a non-zero exit code).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-f</option>, <option>--force</option>
+	  </term>
+	  <listitem>
+	    <para>Force overwriting of output files.  By default, flac warns that the output file already exists and continues to the next file.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-o</option> <replaceable>filename</replaceable>, <option>--output-name</option>=<replaceable>filename</replaceable></term>
+	  <listitem>
+	    <para>Force the output file name (usually flac just changes the extension).  May only be used when encoding a single file.  May not be used in conjunction with --output-prefix.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--output-prefix</option>=<replaceable>string</replaceable></term>
+	  <listitem>
+	    <para>Prefix each output file name with the given string.  This can be useful for encoding or decoding files to a different directory.  Make sure if your string is a path name that it ends with a trailing `/' (slash).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--delete-input-file</option>
+	  </term>
+	  <listitem>
+	    <para>Automatically delete the input file after a successful encode or decode.  If there was an error (including a verify error) the input file is left intact.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--preserve-modtime</option>
+	  </term>
+	  <listitem>
+	    <para>Output files have their timestamps/permissions set to match those of their inputs (this is default).  Use --no-preserve-modtime to make output files have the current time and default permissions.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--keep-foreign-metadata</option>
+	  </term>
+	  <listitem>
+	    <para>If encoding, save WAVE, RF64, or AIFF non-audio chunks in FLAC metadata.  If decoding, restore any saved non-audio chunks from FLAC metadata when writing the decoded file.  Foreign metadata cannot be transcoded, e.g. WAVE chunks saved in a FLAC file cannot be restored when decoding to AIFF.  Input and output must be regular files (not stdin or stdout).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--skip</option>={<replaceable>#</replaceable>|<replaceable>mm:ss.ss</replaceable>}</term>
+	  <listitem>
+	    <para>Skip over the first number of samples of the input.  This works for both encoding and decoding, but not testing.  The alternative form mm:ss.ss can be used to specify minutes, seconds, and fractions of a second.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--until</option>={<replaceable>#</replaceable>|[<replaceable>+</replaceable>|<replaceable>-</replaceable>]<replaceable>mm:ss.ss</replaceable>}</term>
+	  <listitem>
+	    <para>Stop at the given sample number for each input file.  This works for both encoding and decoding, but not testing.  The given sample number is not included in the decoded output.  The alternative form mm:ss.ss can be used to specify minutes, seconds, and fractions of a second.  If a `+' (plus) sign is at the beginning, the --until point is relative to the --skip point.  If a `-' (minus) sign is at the beginning, the --until point is relative to end of the audio.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--ogg</option></term>
+
+	  <listitem>
+	    <para>When encoding, generate Ogg FLAC output instead of native FLAC.  Ogg FLAC streams are FLAC streams wrapped in an Ogg transport layer.  The resulting file should have an '.oga' extension and will still be decodable by flac.</para>
+	    <para>When decoding, force the input to be treated as Ogg FLAC.  This is useful when piping input from stdin or when the filename does not end in '.oga' or '.ogg'.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--serial-number</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>When used with --ogg, specifies the serial number to use for the first Ogg FLAC stream, which is then incremented for each additional stream.  When encoding and no serial number is given, flac uses a random number for the first stream, then increments it for each additional stream.  When decoding and no number is given, flac uses the serial number of the first page.</para>
+	  </listitem>
+	</varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Analysis Options</title>
+
+      <variablelist>
+	<varlistentry>
+	  <term><option>--residual-text</option>
+	  </term>
+	  <listitem>
+	    <para>Includes the residual signal in the analysis file.  This will make the file very big, much larger than even the decoded file.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--residual-gnuplot</option>
+	  </term>
+	  <listitem>
+	    <para>Generates a gnuplot file for every subframe; each file will contain the residual distribution of the subframe.  This will create a lot of files.</para>
+	  </listitem>
+	</varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Decoding Options</title>
+
+      <variablelist>
+	<varlistentry>
+	  <term><option>--cue=[<replaceable>#.#</replaceable>][-[<replaceable>#.#</replaceable>]]</option></term>
+	  <listitem>
+	    <para>Set the beginning and ending cuepoints to decode.  The optional first #.# is the track and index point at which decoding will start; the default is the beginning of the stream.  The optional second #.# is the track and index point at which decoding will end; the default is the end of the stream.  If the cuepoint does not exist, the closest one before it (for the start point) or after it (for the end point) will be used.  If those don't exist, the start of the stream (for the start point) or end of the stream (for the end point) will be used.  The cuepoints are merely translated into sample numbers then used as --skip and --until.  A CD track can always be cued by, for example, --cue=9.1-10.1 for track 9, even if the CD has no 10th track.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-F</option>, <option>--decode-through-errors</option>
+	  </term>
+	  <listitem>
+	    <para>By default flac stops decoding with an error and removes the partially decoded file if it encounters a bitstream error.  With -F, errors are still printed but flac will continue decoding to completion.  Note that errors may cause the decoded audio to be missing some samples or have silent sections.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--apply-replaygain-which-is-not-lossless[=&lt;specification&gt;]</option>
+	  </term>
+	  <listitem>
+            <para>Applies ReplayGain values while decoding.</para>
+            <para>WARNING: THIS IS NOT LOSSLESS.  DECODED AUDIO WILL NOT BE IDENTICAL TO THE ORIGINAL WITH THIS OPTION.</para>
+            <para>The equals sign and &lt;specification&gt; is optional.  If omitted, the default is 0aLn1.</para>
+            <para>The &lt;specification&gt; is a shorthand notation for describing how to apply ReplayGain.  All components are optional but order is important.  '[]' means 'optional'.  '|' means 'or'.  '{}' means required.  The format is:</para>
+            <para>[&lt;preamp&gt;][a|t][l|L][n{0|1|2|3}]</para>
+
+            <variablelist>
+              <varlistentry>
+                <term><option>preamp</option></term>
+                <listitem>
+                  <para>A floating point number in dB.  This is added to the existing gain value.</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term><option>a|t</option></term>
+                <listitem>
+                  <para>Specify 'a' to use the album gain, or 't' to use the track gain.  If tags for the preferred kind (album/track) do not exist but tags for the other (track/album) do, those will be used instead.</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term><option>l|L</option></term>
+                <listitem>
+                  <para>Specify 'l' to peak-limit the output, so that the ReplayGain peak value is full-scale.  Specify 'L' to use a 6dB hard limiter that kicks in when the signal approaches full-scale.</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term><option>n{0|1|2|3}</option></term>
+                <listitem>
+                  <para>Specify the amount of noise shaping.  ReplayGain synthesis happens in floating point; the result is dithered before converting back to integer.  This quantization adds noise.  Noise shaping tries to move the noise where you won't hear it as much.  0 means no noise shaping, 1 means 'low', 2 means 'medium', 3 means 'high'.</para>
+                </listitem>
+              </varlistentry>
+
+            </variablelist>
+
+            <para>For example, the default of 0aLn1 means 0dB preamp, use album gain, 6dB hard limit, low noise shaping.</para>
+            <para>--apply-replaygain-which-is-not-lossless=3 means 3dB preamp, use album gain, no limiting, no noise shaping.</para>
+            <para>flac uses the ReplayGain tags for the calculation.  If a stream does not have the required tags or they can't be parsed, decoding will continue with a warning, and no ReplayGain is applied to that stream.</para>
+	  </listitem>
+	</varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Encoding Options</title>
+
+      <variablelist>
+	<varlistentry>
+	  <term><option>-V</option>, <option>--verify</option></term>
+
+	  <listitem>
+	    <para>Verify a correct encoding by decoding the output in parallel and comparing to the original</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--lax</option></term>
+
+	  <listitem>
+	    <para>Allow encoder to generate non-Subset files.  The resulting FLAC file may not be streamable or might have trouble being played in all players (especially hardware devices), so you should only use this option in combination with custom encoding options meant for archival.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--replay-gain</option></term>
+
+	  <listitem>
+	    <para>Calculate ReplayGain values and store them as FLAC tags, similar to vorbisgain.  Title gains/peaks will be computed for each input file, and an album gain/peak will be computed for all files.  All input files must have the same resolution, sample rate, and number of channels.  Only mono and stereo files are allowed, and the sample rate must be one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, or 48 kHz.  Also note that this option may leave a few extra bytes in a PADDING block as the exact size of the tags is not known until all files are processed.  Note that this option cannot be used when encoding to standard output (stdout).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--cuesheet</option>=<replaceable>filename</replaceable></term>
+
+	  <listitem>
+	    <para>Import the given cuesheet file and store it in a CUESHEET metadata block.  This option may only be used when encoding a single file.  A seekpoint will be added for each index point in the cuesheet to the SEEKTABLE unless --no-cued-seekpoints is specified.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--picture</option>={<replaceable>FILENAME</replaceable>|<replaceable>SPECIFICATION</replaceable>}</term>
+
+	  <listitem>
+	    <para>Import a picture and store it in a PICTURE metadata block.  More than one --picture command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The SPECIFICATION is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  FILENAME is just shorthand for "||||FILENAME".  The format of SPECIFICATION is</para>
+	    <para>[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE</para>
+	    <para>TYPE is optional; it is a number from one of:</para>
+	    <para>0: Other</para>
+	    <para>1: 32x32 pixels 'file icon' (PNG only)</para>
+	    <para>2: Other file icon</para>
+	    <para>3: Cover (front)</para>
+	    <para>4: Cover (back)</para>
+	    <para>5: Leaflet page</para>
+	    <para>6: Media (e.g. label side of CD)</para>
+	    <para>7: Lead artist/lead performer/soloist</para>
+	    <para>8: Artist/performer</para>
+	    <para>9: Conductor</para>
+	    <para>10: Band/Orchestra</para>
+	    <para>11: Composer</para>
+	    <para>12: Lyricist/text writer</para>
+	    <para>13: Recording Location</para>
+	    <para>14: During recording</para>
+	    <para>15: During performance</para>
+	    <para>16: Movie/video screen capture</para>
+	    <para>17: A bright coloured fish</para>
+	    <para>18: Illustration</para>
+	    <para>19: Band/artist logotype</para>
+	    <para>20: Publisher/Studio logotype</para>
+	    <para>The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.</para>
+
+	    <para>MIME-TYPE is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type image/jpeg or image/png.  The MIME type can also be --&gt; to mean that FILE is actually a URL to an image, though this use is discouraged.</para>
+
+	    <para>DESCRIPTION is optional; the default is an empty string.</para>
+
+	    <para>The next part specifies the resolution and color information.  If the MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.</para>
+
+	    <para>FILE is the path to the picture file to be imported, or the URL if MIME type is --&gt;</para>
+
+	    <para>For example, "|image/jpeg|||../cover.jpg" will embed the JPEG file at ../cover.jpg, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.</para>
+
+	    <para>The specification "4|-->|CD|320x300x24/173|http://blah.blah/backcover.tiff" will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--sector-align</option></term>
+
+	  <listitem>
+	    <para>Align encoding of multiple CD format files on sector boundaries.  See the HTML documentation for more information.  This option is DEPRECATED and may not exist in future versions of flac.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--ignore-chunk-sizes</option></term>
+
+	  <listitem>
+		<para>When encoding to flac, ignore the file size headers in WAV and AIFF files to attempt to work around problems with over-sized or malformed files.</para>
+		<para>WAV and AIFF files both have an unsigned 32 bit numbers in the file header which specifes the length of audio data. Since this number is unsigned 32 bits, that limits the size of a valid file to being just over 4 Gigabytes. Files larger than this are mal-formed, but should be read correctly using this option.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-S</option> {<replaceable>#</replaceable>|<replaceable>X</replaceable>|<replaceable>#x</replaceable>|<replaceable>#s</replaceable>}, <option>--seekpoint</option>={<replaceable>#</replaceable>|<replaceable>X</replaceable>|<replaceable>#x</replaceable>|<replaceable>#s</replaceable>}</term>
+
+	  <listitem>
+	    <para>Include a point or points in a SEEKTABLE.  Using #, a seek point at that sample number is added.  Using X, a placeholder point is added at the end of a the table.  Using #x, # evenly spaced seek points will be added, the first being at sample 0.  Using #s, a seekpoint will be added every # seconds (# does not have to be a whole number; it can be, for example, 9.5, meaning a seekpoint every 9.5 seconds).  You may use many -S options; the resulting SEEKTABLE will be the unique-ified union of all such values.  With no -S options, flac defaults to '-S 10s'.  Use --no-seektable for no SEEKTABLE.  Note: '-S #x' and '-S #s' will not work if the encoder can't determine the input size before starting.  Note: if you use '-S #' and # is >= samples in the input, there will be either no seek point entered (if the input size is determinable before encoding starts) or a placeholder point (if input size is not determinable).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-P</option> <replaceable>#</replaceable>, <option>--padding</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Tell the encoder to write a PADDING metadata block of the given length (in bytes) after the STREAMINFO block.  This is useful if you plan to tag the file later with an APPLICATION block; instead of having to rewrite the entire file later just to insert your block, you can write directly over the PADDING block.  Note that the total length of the PADDING block will be 4 bytes longer than the length given because of the 4 metadata block header bytes.  You can force no PADDING block at all to be written with --no-padding.  The encoder writes a PADDING block of 8192 bytes by default (or 65536 bytes if the input audio stream is more that 20 minutes long).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-T</option> <replaceable>FIELD=VALUE</replaceable>, <option>--tag</option>=<replaceable>FIELD=VALUE</replaceable></term>
+
+	  <listitem>
+	    <para>Add a FLAC tag.  The comment must adhere to the Vorbis comment spec; i.e. the FIELD must contain only legal characters, terminated by an 'equals' sign.  Make sure to quote the comment if necessary.  This option may appear more than once to add several comments.  NOTE: all tags will be added to all encoded files.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--tag-from-file</option>=<replaceable>FIELD=FILENAME</replaceable></term>
+
+	  <listitem>
+	    <para>Like --tag, except FILENAME is a file whose contents will be read verbatim to set the tag value.  The contents will be converted to UTF-8 from the local charset.  This can be used to store a cuesheet in a tag (e.g.  --tag-from-file="CUESHEET=image.cue").  Do not try to store binary data in tag fields!  Use APPLICATION blocks for that.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-b</option> <replaceable>#</replaceable>, <option>--blocksize</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Specify the block size in samples.  Subset streams must use one of 192, 576, 1152, 2304, 4608, 256, 512, 1024, 2048, 4096 (and 8192 or 16384 if the sample rate is &gt;48kHz).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-m</option>, <option>--mid-side</option></term>
+
+	  <listitem>
+	    <para>Try mid-side coding for each frame (stereo input only)</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-M</option>, <option>--adaptive-mid-side</option></term>
+
+	  <listitem>
+	    <para>Adaptive mid-side coding for all frames (stereo input only)</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-0</option>..<option>-8</option>, <option>--compression-level-0</option>..<option>--compression-level-8</option></term>
+
+	  <listitem>
+	    <para>Fastest compression..highest compression (default is -5).  These are synonyms for other options:</para>
+
+	    <variablelist>
+	      <varlistentry>
+		<term><option>-0</option>, <option>--compression-level-0</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 0 -b 1152 -r 3</para>
+		</listitem>
+	      </varlistentry>
+
+	      <varlistentry>
+		<term><option>-1</option>, <option>--compression-level-1</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 0 -b 1152 -M -r 3</para>
+		</listitem>
+	      </varlistentry>
+
+	      <varlistentry>
+		<term><option>-2</option>, <option>--compression-level-2</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 0 -b 1152 -m -r 3</para>
+		</listitem>
+	      </varlistentry>
+
+	      <varlistentry>
+		<term><option>-3</option>, <option>--compression-level-3</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 6 -b 4096 -r 4</para>
+		</listitem>
+	      </varlistentry>
+
+	      <varlistentry>
+		<term><option>-4</option>, <option>--compression-level-4</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 8 -b 4096 -M -r 4</para>
+		</listitem>
+	      </varlistentry>
+
+	      <varlistentry>
+		<term><option>-5</option>, <option>--compression-level-5</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 8 -b 4096 -m -r 5</para>
+		</listitem>
+	      </varlistentry>
+
+	      <varlistentry>
+		<term><option>-6</option>, <option>--compression-level-6</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 8 -b 4096 -m -r 6 -A tukey(0.5) -A partial_tukey(2)</para>
+		</listitem>
+	      </varlistentry>
+
+	      <varlistentry>
+		<term><option>-7</option>, <option>--compression-level-7</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 8 -b 4096 -m -e -r 6 -A tukey(0.5) -A partial_tukey(2)</para>
+		</listitem>
+	      </varlistentry>
+
+	      <varlistentry>
+		<term><option>-8</option>, <option>--compression-level-8</option></term>
+
+		<listitem>
+		  <para>Synonymous with -l 12 -b 4096 -m -e -r 6 -A tukey(0.5) -A partial_tukey(2) -A punchout_tukey(3)</para>
+		</listitem>
+	      </varlistentry>
+	    </variablelist>
+
+	  </listitem>
+
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--fast</option></term>
+
+	  <listitem>
+	    <para>Fastest compression.  Currently synonymous with -0.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--best</option></term>
+
+	  <listitem>
+	    <para>Highest compression.  Currently synonymous with -8.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-e</option>, <option>--exhaustive-model-search</option></term>
+
+	  <listitem>
+	    <para>Do exhaustive model search (expensive!)</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-A</option> <replaceable>function</replaceable>, <option>--apodization</option>=<replaceable>function</replaceable></term>
+
+	  <listitem>
+	    <para>Window audio data with given the apodization function.  The functions are: bartlett, bartlett_hann, blackman, blackman_harris_4term_92db, connes, flattop, gauss(STDDEV), hamming, hann, kaiser_bessel, nuttall, rectangle, triangle, tukey(P), partial_tukey(n[/ov[/P]]), punchout_tukey(n[/ov[/P]]), welch.</para>
+	    <para>For gauss(STDDEV), STDDEV is the standard deviation (0&lt;STDDEV&lt;=0.5).</para>
+	    <para>For tukey(P), P specifies the fraction of the window that is tapered (0&lt;=P&lt;=1; P=0 corresponds to "rectangle" and P=1 corresponds to "hann").</para>
+	    <para>For partial_tukey(n) and punchout_tukey(n), n apodization functions are added that span different parts of each block. Values of 2 to 6 seem to yield sane results. If necessary, an overlap can be specified, as can be the taper parameter, for example partial_tukey(2/0.2) or partial_tukey(2/0.2/0.5). ov should be smaller than 1 and can be negative.</para>
+	    <para>Please note that P, STDDEV and ov are locale specific, so a comma as decimal separator might be required instead of a dot.</para>
+	    <para>More than one -A option (up to 32) may be used.  Any function that is specified erroneously is silently dropped.  The encoder chooses suitable defaults in the absence of any -A options; any -A option specified replaces the default(s).</para>
+	    <para>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.  Multiple functions can greatly increase the encoding time.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-l</option> <replaceable>#</replaceable>, <option>--max-lpc-order</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Specifies the maximum LPC order. This number must be &lt;= 32. For Subset streams, it must be &lt;=12 if the sample rate is &lt;=48kHz. If 0, the encoder will not attempt generic linear prediction, and use only fixed predictors. Using fixed predictors is faster but usually results in files being 5-10% larger.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-p</option>, <option>--qlp-coeff-precision-search</option></term>
+
+	  <listitem>
+	    <para>Do exhaustive search of LP coefficient quantization (expensive!).  Overrides -q; does nothing if using -l 0</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-q</option> <replaceable>#</replaceable>, <option>--qlp-coeff-precision</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Precision of the quantized linear-predictor coefficients, 0 => let encoder decide (min is 5, default is 0)</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-r</option> [<replaceable>#</replaceable>,]<replaceable>#</replaceable>, <option>--rice-partition-order</option>=[<replaceable>#</replaceable>,]<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Set the [min,]max residual partition order (0..15). min defaults to 0 if unspecified.  Default is -r 5.</para>
+	  </listitem>
+	</varlistentry>
+
+      </variablelist>
+
+    </refsect2>
+    <refsect2>
+      <title>Format Options</title>
+
+      <variablelist>
+	<varlistentry>
+	  <term><option>--endian</option>={<replaceable>big</replaceable>|<replaceable>little</replaceable>}</term>
+
+	  <listitem>
+	    <para>Set the byte order for samples</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--channels</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Set number of channels.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--bps</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Set bits per sample.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--sample-rate</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Set sample rate (in Hz).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--sign</option>={<replaceable>signed</replaceable>|<replaceable>unsigned</replaceable>}</term>
+
+	  <listitem>
+	    <para>Set the sign of samples (the default is signed).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--input-size</option>=<replaceable>#</replaceable></term>
+
+	  <listitem>
+	    <para>Specify the size of the raw input in bytes.  If you are encoding raw samples from stdin, you must set this option in order to be able to use --skip, --until, --cuesheet, or other options that need to know the size of the input beforehand.  If the size given is greater than what is found in the input stream, the encoder will complain about an unexpected end-of-file.  If the size given is less, samples will be truncated.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--force-raw-format</option></term>
+
+	  <listitem>
+	    <para>Force input (when encoding) or output (when decoding) to be treated as raw samples (even if filename ends in <filename>.wav</filename>).</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--force-aiff-format</option></term>
+
+	  <listitem>
+	    <para>Force the decoder to output AIFF format.  This option is not needed if the output filename (as set by -o) ends with <filename>.aif</filename> or <filename>.aiff</filename>.  Also, this option has no effect when encoding since input AIFF is auto-detected.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--force-rf64-format</option></term>
+
+	  <listitem>
+	    <para>Force the decoder to output RF64 format.  This option is not needed if the output filename (as set by -o) ends with <filename>.rf64</filename>.  Also, this option has no effect when encoding since input RF64 is auto-detected.</para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>--force-wave64-format</option></term>
+
+	  <listitem>
+	    <para>Force the decoder to output Wave64 format.  This option is not needed if the output filename (as set by -o) ends with <filename>.w64</filename>.  Also, this option has no effect when encoding since input Wave64 is auto-detected.</para>
+	  </listitem>
+	</varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Negative Options</title>
+
+      <variablelist>
+	<varlistentry>
+	  <term><option>--no-adaptive-mid-side</option></term>
+	  <term><option>--no-cued-seekpoints</option></term>
+	  <term><option>--no-decode-through-errors</option></term>
+	  <term><option>--no-delete-input-file</option></term>
+	  <term><option>--no-preserve-modtime</option></term>
+	  <term><option>--no-keep-foreign-metadata</option></term>
+	  <term><option>--no-exhaustive-model-search</option></term>
+	  <term><option>--no-force</option></term>
+	  <term><option>--no-lax</option></term>
+	  <term><option>--no-mid-side</option></term>
+	  <term><option>--no-ogg</option></term>
+	  <term><option>--no-padding</option></term>
+	  <term><option>--no-qlp-coeff-prec-search</option></term>
+	  <term><option>--no-replay-gain</option></term>
+	  <term><option>--no-residual-gnuplot</option></term>
+	  <term><option>--no-residual-text</option></term>
+	  <term><option>--no-sector-align</option></term>
+	  <term><option>--no-seektable</option></term>
+	  <term><option>--no-silent</option></term>
+	  <term><option>--no-verify</option></term>
+	  <term><option>--no-warnings-as-errors</option></term>
+	  <listitem>
+	    <para>These flags can be used to invert the sense of the corresponding normal option.</para>
+	  </listitem>
+	</varlistentry>
+      </variablelist>
+
+    </refsect2>
+
+  </refsect1>
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para>metaflac(1)</para>
+
+    <para>The programs are documented fully by HTML format documentation, available in <filename>/usr/share/doc/libflac-doc/html</filename> on &debian; systems.</para>
+  </refsect1>
+  <refsect1>
+    <title>AUTHOR</title>
+
+    <para>This manual page was initially written by &dhusername; &dhemail; for the &debian; system (but may be used by others). It has been kept up-to-date by the Xiph.org Foundation.</para>
+
+    <!-- <para>Permission is granted to copy, distribute and/or modify this document under the terms of the <acronym>GNU</acronym> Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts.  A copy of the license can be found under <filename>/usr/share/common-licenses/FDL</filename>.</para> -->
+
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+      Local variables:
+      mode: sgml
+      sgml-omittag:t
+      sgml-shorttag:t
+      sgml-minimize-attributes:nil
+      sgml-always-quote-attributes:t
+      sgml-indent-step:2
+      sgml-indent-data:t
+      sgml-parent-document:nil
+      sgml-default-dtd-file:nil
+      sgml-exposed-tags:nil
+      sgml-local-catalogs:nil
+      sgml-local-ecat-files:nil
+      End:
+      -->
diff --git a/man/metaflac.1 b/man/metaflac.1
new file mode 100644
index 0000000..0c1c66b
--- /dev/null
+++ b/man/metaflac.1
@@ -0,0 +1,304 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "METAFLAC" "1" "2013/04/30" "" ""
+
+.SH NAME
+metaflac \- program to list, add, remove, or edit metadata in one or more FLAC files.
+.SH SYNOPSIS
+
+\fBmetaflac\fR [ \fB\fIoptions\fB\fR ] [ \fB\fIoperations\fB\fR ] \fB\fIFLACfile\fB\fR\fI ...\fR
+
+.SH "DESCRIPTION"
+.PP
+Use \fBmetaflac\fR to list, add, remove, or edit
+metadata in one or more FLAC files.  You may perform one major operation,
+or many shorthand operations at a time.
+.SH "OPTIONS"
+.TP
+\fB--preserve-modtime\fR
+Preserve the original modification time in spite of edits.
+.TP
+\fB--with-filename\fR
+Prefix each output line with the FLAC file name (the default if
+more than one FLAC file is specified).
+.TP
+\fB--no-filename\fR
+Do not prefix each output line with the FLAC file name (the default
+if only one FLAC file is specified).
+.TP
+\fB--no-utf8-convert\fR
+Do not convert tags from UTF-8 to local charset, or vice versa. This is
+useful for scripts, and setting tags in situations where the locale is wrong.
+.TP
+\fB--dont-use-padding\fR
+By default metaflac tries to use padding where possible to avoid
+rewriting the entire file if the metadata size changes.  Use this
+option to tell metaflac to not take advantage of padding this way.
+.SH "SHORTHAND OPERATIONS"
+.TP
+\fB--show-md5sum\fR
+Show the MD5 signature from the STREAMINFO block.
+.TP
+\fB--show-min-blocksize\fR
+Show the minimum block size from the STREAMINFO block.
+.TP
+\fB--show-max-blocksize\fR
+Show the maximum block size from the STREAMINFO block.
+.TP
+\fB--show-min-framesize\fR
+Show the minimum frame size from the STREAMINFO block.
+.TP
+\fB--show-max-framesize\fR
+Show the maximum frame size from the STREAMINFO block.
+.TP
+\fB--show-sample-rate\fR
+Show the sample rate from the STREAMINFO block.
+.TP
+\fB--show-channels\fR
+Show the number of channels from the STREAMINFO block.
+.TP
+\fB--show-bps\fR
+Show the # of bits per sample from the STREAMINFO block.
+.TP
+\fB--show-total-samples\fR
+Show the total # of samples from the STREAMINFO block.
+.TP
+\fB--show-vendor-tag\fR
+Show the vendor string from the VORBIS_COMMENT block.
+.TP
+\fB--show-tag=name\fR
+Show all tags where the field name matches 'name'.
+.TP
+\fB--remove-tag=name\fR
+Remove all tags whose field name is 'name'.
+.TP
+\fB--remove-first-tag=name\fR
+Remove first tag whose field name is 'name'.
+.TP
+\fB--remove-all-tags\fR
+Remove all tags, leaving only the vendor string.
+.TP
+\fB--set-tag=field\fR
+Add a tag.  The field must comply with the
+Vorbis comment spec, of the form "NAME=VALUE".  If there is
+currently no tag block, one will be created.
+.TP
+\fB--set-tag-from-file=field\fR
+Like --set-tag, except the VALUE is a filename whose
+contents will be read verbatim to set the tag value.
+Unless --no-utf8-convert is specified, the contents will be
+converted to UTF-8 from the local charset.  This can be used
+to store a cuesheet in a tag (e.g.
+--set-tag-from-file="CUESHEET=image.cue").  Do not try to
+store binary data in tag fields!  Use APPLICATION blocks for
+that.
+.TP
+\fB--import-tags-from=file\fR
+Import tags from a file.  Use '-' for stdin.  Each
+line should be of the form NAME=VALUE.  Multi-line comments
+are currently not supported.  Specify --remove-all-tags and/or
+--no-utf8-convert before --import-tags-from if necessary.  If
+FILE is '-' (stdin), only one FLAC file may be specified.
+.TP
+\fB--export-tags-to=file\fR
+Export tags to a file.  Use '-' for stdout.  Each
+line will be of the form NAME=VALUE.  Specify
+--no-utf8-convert if necessary.
+.TP
+\fB--import-cuesheet-from=file\fR
+Import a cuesheet from a file.  Use '-' for stdin.  Only one
+FLAC file may be specified.  A seekpoint will be added for each
+index point in the cuesheet to the SEEKTABLE unless
+--no-cued-seekpoints is specified.
+.TP
+\fB--export-cuesheet-to=file\fR
+Export CUESHEET block to a cuesheet file, suitable for use by
+CD authoring software.  Use '-' for stdout.  Only one FLAC file
+may be specified on the command line.
+.TP
+\fB--import-picture-from={\fIFILENAME\fB|\fISPECIFICATION\fB}\fR
+Import a picture and store it in a PICTURE metadata block.  More than one --import-picture-from command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The SPECIFICATION is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  FILENAME is just shorthand for "||||FILENAME".  The format of SPECIFICATION is
+
+[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE
+
+TYPE is optional; it is a number from one of:
+
+0: Other
+
+1: 32x32 pixels 'file icon' (PNG only)
+
+2: Other file icon
+
+3: Cover (front)
+
+4: Cover (back)
+
+5: Leaflet page
+
+6: Media (e.g. label side of CD)
+
+7: Lead artist/lead performer/soloist
+
+8: Artist/performer
+
+9: Conductor
+
+10: Band/Orchestra
+
+11: Composer
+
+12: Lyricist/text writer
+
+13: Recording Location
+
+14: During recording
+
+15: During performance
+
+16: Movie/video screen capture
+
+17: A bright coloured fish
+
+18: Illustration
+
+19: Band/artist logotype
+
+20: Publisher/Studio logotype
+
+The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.
+
+MIME-TYPE is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type image/jpeg or image/png.  The MIME type can also be --> to mean that FILE is actually a URL to an image, though this use is discouraged.
+
+DESCRIPTION is optional; the default is an empty string.
+
+The next part specifies the resolution and color information.  If the MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.
+
+FILE is the path to the picture file to be imported, or the URL if MIME type is -->
+
+For example, "|image/jpeg|||../cover.jpg" will embed the JPEG file at ../cover.jpg, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.
+
+The specification "4|-->|CD|320x300x24/173|http://blah.blah/backcover.tiff" will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.
+.TP
+\fB--export-picture-to=file\fR
+Export PICTURE block to a file.  Use '-' for stdout.  Only one FLAC file may be specified on the command line.  The first PICTURE block will be exported unless --export-picture-to is preceded by a --block-number=# option to specify the exact metadata block to extract.  Note that the block number is the one shown by --list.
+.TP
+\fB--add-replay-gain\fR
+Calculates the title and album gains/peaks of the given FLAC
+files as if all the files were part of one album, then stores
+them as FLAC tags.  The tags are the same as
+those used by vorbisgain.  Existing ReplayGain tags will be
+replaced.  If only one FLAC file is given, the album and title
+gains will be the same.  Since this operation requires two
+passes, it is always executed last, after all other operations
+have been completed and written to disk.  All FLAC files
+specified must have the same resolution, sample rate, and
+number of channels.  The sample rate must be one of 8, 11.025,
+12, 16, 18.9, 22.05, 24, 28, 32, 37.8, 44.1, 48, 56, 64, 88.2,
+96, 112, 128, 144, 176.4, or 192kHz.
+.TP
+\fB--scan-replay-gain\fR
+Like --add-replay-gain, but only analyzes the files rather than
+writing them to the tags.
+.TP
+\fB--remove-replay-gain\fR
+Removes the ReplayGain tags.
+.TP
+\fB--add-seekpoint={\fI#\fB|\fIX\fB|\fI#x\fB|\fI#s\fB}\fR
+Add seek points to a SEEKTABLE block.  Using #, a seek point at
+that sample number is added.  Using X, a placeholder point is
+added at the end of a the table.  Using #x, # evenly spaced seek
+points will be added, the first being at sample 0.  Using #s, a
+seekpoint will be added every # seconds (# does not have to be a
+whole number; it can be, for example, 9.5, meaning a seekpoint
+every 9.5 seconds).  If no SEEKTABLE block exists, one will be
+created.  If one already exists, points will be added to the
+existing table, and any duplicates will be turned into placeholder
+points.  You may use many --add-seekpoint options; the resulting
+SEEKTABLE will be the unique-ified union of all such values.
+Example: --add-seekpoint=100x --add-seekpoint=3.5s will add 100
+evenly spaced seekpoints and a seekpoint every 3.5 seconds.
+.TP
+\fB--add-padding=length\fR
+Add a padding block of the given length (in bytes).  The overall
+length of the new block will be 4 + length; the extra 4 bytes is
+for the metadata block header.
+.SH "MAJOR OPERATIONS"
+.TP
+\fB--list\fR
+List the contents of one or more metadata blocks to stdout.  By
+default, all metadata blocks are listed in text format.  Use the
+following options to change this behavior:
+.RS
+.TP
+\fB--block-number=#[,#[...]]\fR
+An optional comma-separated list of block numbers to display.
+The first block, the STREAMINFO block, is block 0.
+.TP
+\fB--block-type=type[,type[...]]\fR
+.TP
+\fB--except-block-type=type[,type[...]]\fR
+An optional comma-separated list of block types to be included
+or ignored with this option.  Use only one of --block-type or
+--except-block-type.  The valid block types are: STREAMINFO,
+PADDING, APPLICATION, SEEKTABLE, VORBIS_COMMENT, PICTURE.  You
+may narrow down the types of APPLICATION blocks displayed as
+follows:
+
+APPLICATION:abcd        The APPLICATION block(s) whose textual repre-
+sentation of the 4-byte ID is "abcd"
+APPLICATION:0xXXXXXXXX  The APPLICATION block(s) whose hexadecimal big-
+endian representation of the 4-byte ID is
+"0xXXXXXXXX".  For the example "abcd" above the
+hexadecimal equivalalent is 0x61626364
+.sp
+.RS
+.B "Note:"
+if both --block-number and --[except-]block-type are
+specified, the result is the logical AND of both
+arguments.
+.RE
+.TP
+\fB--application-data-format=hexdump|text\fR
+If the application block you are displaying contains binary
+data but your --data-format=text, you can display a hex dump
+of the application data contents instead using
+--application-data-format=hexdump.
+.RE
+.TP
+\fB--remove\fR
+Remove one or more metadata blocks from the metadata.  Unless
+--dont-use-padding is specified, the blocks will be replaced with
+padding.  You may not remove the STREAMINFO block.
+.RS
+.TP
+\fB--block-number=#[,#[...]]\fR
+.TP
+\fB--block-type=type[,type[...]]\fR
+.TP
+\fB--except-block-type=type[,type[...]]\fR
+See --list above for usage.
+.sp
+.RS
+.B "Note:"
+if both --block-number and --[except-]block-type are
+specified, the result is the logical AND of both arguments.
+.RE
+.RE
+.TP
+\fB--remove-all\fR
+Remove all metadata blocks (except the STREAMINFO block) from the
+metadata.  Unless --dont-use-padding is specified, the blocks will
+be replaced with padding.
+.TP
+\fB--merge-padding\fR
+Merge adjacent PADDING blocks into single blocks.
+.TP
+\fB--sort-padding\fR
+Move all PADDING blocks to the end of the metadata and merge them
+into a single block.
+.SH "SEE ALSO"
+.PP
+flac(1).
diff --git a/man/metaflac.sgml b/man/metaflac.sgml
new file mode 100644
index 0000000..219cca4
--- /dev/null
+++ b/man/metaflac.sgml
@@ -0,0 +1,581 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+
+<!-- Process this file with docbook-to-man to generate an nroff manual
+     page: `docbook-to-man manpage.sgml > manpage.1'.  You may view
+     the manual page with: `docbook-to-man manpage.sgml | nroff -man |
+     less'.  A typical entry in a Makefile or Makefile.am is:
+
+manpage.1: manpage.sgml
+	docbook-to-man $< > $@
+  -->
+
+<!-- This is based on an example constructed by Colin Watson
+     <email>cjwatson@debian.org</email>, based on a man page template
+     provided by Tom Christiansen <email>tchrist@jhereg.perl.com</email>
+     and a DocBook man page example by Craig Small
+     <email>csmall@debian.org</email>.
+  -->
+
+  <!-- Fill in the various UPPER CASE things here. -->
+  <!ENTITY manfirstname "<firstname>dann</firstname>">
+  <!ENTITY mansurname   "<surname>frazier</surname>">
+  <!-- Please adjust the date whenever revising the manpage. -->
+  <!ENTITY mandate      "<date>2013/04/30</date>">
+  <!-- SECTION should be 1-8, maybe with subsection. Other parameters are
+       allowed: see man(7), man(1). -->
+  <!ENTITY mansection   "<manvolnum>1</manvolnum>">
+  <!ENTITY manemail     "<email>dannf@debian.org</email>">
+  <!ENTITY manusername  "dannf">
+  <!ENTITY manucpackage "<refentrytitle>METAFLAC</refentrytitle>">
+  <!ENTITY manpackage   "metaflac">
+]>
+
+<refentry>
+  <refentryinfo>
+    <address>
+      &manemail;
+    </address>
+    <author>
+      &manfirstname;
+      &mansurname;
+    </author>
+    <copyright>
+      <year>2002-2005, 2011-2013</year>
+      <holder>&manusername;</holder>
+    </copyright>
+    &mandate;
+  </refentryinfo>
+  <refmeta>
+    &manucpackage;
+
+    &mansection;
+  </refmeta>
+  <refnamediv>
+    <refname>&manpackage;</refname>
+
+    <refpurpose>
+      program to list, add, remove, or edit metadata in one or more FLAC files.
+    </refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>&manpackage;</command>
+
+      <group choice="opt"><arg><replaceable>options</replaceable></arg></group>
+      <group choice="opt">
+	<arg><replaceable>operations</replaceable></arg></group>
+      <arg rep="repeat" choice="req"><replaceable>FLACfile</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para>Use <command>&manpackage;</command> to list, add, remove, or edit
+      metadata in one or more FLAC files.  You may perform one major operation,
+      or many shorthand operations at a time.</para>
+
+  </refsect1>
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist>
+      <varlistentry>
+        <term><option>--preserve-modtime</option></term>
+        <listitem>
+          <para>
+	    Preserve the original modification time in spite of edits.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--with-filename</option></term>
+        <listitem>
+          <para>
+	    Prefix each output line with the FLAC file name (the default if
+	    more than one FLAC file is specified).
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--no-filename</option></term>
+        <listitem>
+          <para>
+	    Do not prefix each output line with the FLAC file name (the default
+	    if only one FLAC file is specified).
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--no-utf8-convert</option></term>
+        <listitem>
+          <para>
+	    Do not convert tags from UTF-8 to local charset, or vice versa. This is
+	    useful for scripts, and setting tags in situations where the locale is wrong.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--dont-use-padding</option></term>
+        <listitem>
+          <para>
+	    By default metaflac tries to use padding where possible to avoid
+	    rewriting the entire file if the metadata size changes.  Use this
+	    option to tell metaflac to not take advantage of padding this way.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>SHORTHAND OPERATIONS</title>
+
+    <variablelist>
+      <varlistentry>
+        <term><option>--show-md5sum</option></term>
+        <listitem>
+          <para>
+	    Show the MD5 signature from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-min-blocksize</option></term>
+        <listitem>
+          <para>
+	    Show the minimum block size from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-max-blocksize</option></term>
+        <listitem>
+          <para>
+	    Show the maximum block size from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-min-framesize</option></term>
+        <listitem>
+          <para>
+	    Show the minimum frame size from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-max-framesize</option></term>
+        <listitem>
+          <para>
+	    Show the maximum frame size from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-sample-rate</option></term>
+        <listitem>
+          <para>
+	    Show the sample rate from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-channels</option></term>
+        <listitem>
+          <para>
+	    Show the number of channels from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-bps</option></term>
+        <listitem>
+          <para>
+	    Show the # of bits per sample from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-total-samples</option></term>
+        <listitem>
+          <para>
+	    Show the total # of samples from the STREAMINFO block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-vendor-tag</option></term>
+        <listitem>
+          <para>
+	    Show the vendor string from the VORBIS_COMMENT block.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-tag=name</option></term>
+        <listitem>
+          <para>
+	    Show all tags where the field name matches 'name'.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove-tag=name</option></term>
+        <listitem>
+          <para>
+	    Remove all tags whose field name is 'name'.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove-first-tag=name</option></term>
+        <listitem>
+          <para>
+	    Remove first tag whose field name is 'name'.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove-all-tags</option></term>
+        <listitem>
+          <para>
+	    Remove all tags, leaving only the vendor string.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--set-tag=field</option></term>
+        <listitem>
+          <para>
+	    Add a tag.  The field must comply with the
+	    Vorbis comment spec, of the form "NAME=VALUE".  If there is
+	    currently no tag block, one will be created.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--set-tag-from-file=field</option></term>
+        <listitem>
+          <para>
+	    Like --set-tag, except the VALUE is a filename whose
+	    contents will be read verbatim to set the tag value.
+	    Unless --no-utf8-convert is specified, the contents will be
+	    converted to UTF-8 from the local charset.  This can be used
+	    to store a cuesheet in a tag (e.g.
+	    --set-tag-from-file="CUESHEET=image.cue").  Do not try to
+	    store binary data in tag fields!  Use APPLICATION blocks for
+	    that.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--import-tags-from=file</option></term>
+        <listitem>
+	  <para>
+	    Import tags from a file.  Use '-' for stdin.  Each
+	    line should be of the form NAME=VALUE.  Multi-line comments
+	    are currently not supported.  Specify --remove-all-tags and/or
+	    --no-utf8-convert before --import-tags-from if necessary.  If
+	    FILE is '-' (stdin), only one FLAC file may be specified.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--export-tags-to=file</option></term>
+        <listitem>
+	  <para>
+	    Export tags to a file.  Use '-' for stdout.  Each
+	    line will be of the form NAME=VALUE.  Specify
+	    --no-utf8-convert if necessary.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--import-cuesheet-from=file</option></term>
+        <listitem>
+	  <para>
+	    Import a cuesheet from a file.  Use '-' for stdin.  Only one
+	    FLAC file may be specified.  A seekpoint will be added for each
+	    index point in the cuesheet to the SEEKTABLE unless
+	    --no-cued-seekpoints is specified.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--export-cuesheet-to=file</option></term>
+        <listitem>
+	  <para>
+	    Export CUESHEET block to a cuesheet file, suitable for use by
+	    CD authoring software.  Use '-' for stdout.  Only one FLAC file
+	    may be specified on the command line.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--import-picture-from</option>={<replaceable>FILENAME</replaceable>|<replaceable>SPECIFICATION</replaceable>}</term>
+	<listitem>
+	  <para>Import a picture and store it in a PICTURE metadata block.  More than one --import-picture-from command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The SPECIFICATION is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  FILENAME is just shorthand for "||||FILENAME".  The format of SPECIFICATION is</para>
+	  <para>[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE</para>
+	  <para>TYPE is optional; it is a number from one of:</para>
+	  <para>0: Other</para>
+	  <para>1: 32x32 pixels 'file icon' (PNG only)</para>
+	  <para>2: Other file icon</para>
+	  <para>3: Cover (front)</para>
+	  <para>4: Cover (back)</para>
+	  <para>5: Leaflet page</para>
+	  <para>6: Media (e.g. label side of CD)</para>
+	  <para>7: Lead artist/lead performer/soloist</para>
+	  <para>8: Artist/performer</para>
+	  <para>9: Conductor</para>
+	  <para>10: Band/Orchestra</para>
+	  <para>11: Composer</para>
+	  <para>12: Lyricist/text writer</para>
+	  <para>13: Recording Location</para>
+	  <para>14: During recording</para>
+	  <para>15: During performance</para>
+	  <para>16: Movie/video screen capture</para>
+	  <para>17: A bright coloured fish</para>
+	  <para>18: Illustration</para>
+	  <para>19: Band/artist logotype</para>
+	  <para>20: Publisher/Studio logotype</para>
+	  <para>The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.</para>
+
+	  <para>MIME-TYPE is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type image/jpeg or image/png.  The MIME type can also be --&gt; to mean that FILE is actually a URL to an image, though this use is discouraged.</para>
+
+	  <para>DESCRIPTION is optional; the default is an empty string.</para>
+
+	  <para>The next part specifies the resolution and color information.  If the MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.</para>
+
+	  <para>FILE is the path to the picture file to be imported, or the URL if MIME type is --&gt;</para>
+
+	  <para>For example, "|image/jpeg|||../cover.jpg" will embed the JPEG file at ../cover.jpg, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.</para>
+
+	  <para>The specification "4|-->|CD|320x300x24/173|http://blah.blah/backcover.tiff" will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--export-picture-to=file</option></term>
+        <listitem>
+	  <para>
+	    Export PICTURE block to a file.  Use '-' for stdout.  Only one FLAC file may be specified on the command line.  The first PICTURE block will be exported unless --export-picture-to is preceded by a --block-number=# option to specify the exact metadata block to extract.  Note that the block number is the one shown by --list.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--add-replay-gain</option></term>
+        <listitem>
+	  <para>
+	    Calculates the title and album gains/peaks of the given FLAC
+	    files as if all the files were part of one album, then stores
+	    them as FLAC tags.  The tags are the same as
+	    those used by vorbisgain.  Existing ReplayGain tags will be
+	    replaced.  If only one FLAC file is given, the album and title
+	    gains will be the same.  Since this operation requires two
+	    passes, it is always executed last, after all other operations
+	    have been completed and written to disk.  All FLAC files
+	    specified must have the same resolution, sample rate, and
+	    number of channels.  The sample rate must be one of 8, 11.025,
+	    12, 16, 18.9, 22.05, 24, 28, 32, 37.8, 44.1, 48, 56, 64, 88.2,
+	    96, 112, 128, 144, 176.4, or 192kHz.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--scan-replay-gain</option></term>
+        <listitem>
+	  <para>
+            
+	    Like --add-replay-gain, but only analyzes the files rather
+	    than writing them to the tags.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--remove-replay-gain</option></term>
+        <listitem>
+	  <para>
+	    Removes the ReplayGain tags.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>--add-seekpoint</option>={<replaceable>#</replaceable>|<replaceable>X</replaceable>|<replaceable>#x</replaceable>|<replaceable>#s</replaceable>}</term>
+	<listitem>
+	  <para>
+	    Add seek points to a SEEKTABLE block.  Using #, a seek point at
+	    that sample number is added.  Using X, a placeholder point is
+	    added at the end of a the table.  Using #x, # evenly spaced seek
+	    points will be added, the first being at sample 0.  Using #s, a
+	    seekpoint will be added every # seconds (# does not have to be a
+	    whole number; it can be, for example, 9.5, meaning a seekpoint
+	    every 9.5 seconds).  If no SEEKTABLE block exists, one will be
+	    created.  If one already exists, points will be added to the
+	    existing table, and any duplicates will be turned into placeholder
+	    points.  You may use many --add-seekpoint options; the resulting
+	    SEEKTABLE will be the unique-ified union of all such values.
+	    Example: --add-seekpoint=100x --add-seekpoint=3.5s will add 100
+	    evenly spaced seekpoints and a seekpoint every 3.5 seconds.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--add-padding=length</option></term>
+        <listitem>
+          <para>
+	    Add a padding block of the given length (in bytes).  The overall
+	    length of the new block will be 4 + length; the extra 4 bytes is
+	    for the metadata block header.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>MAJOR OPERATIONS</title>
+
+    <variablelist>
+      <varlistentry>
+        <term><option>--list</option></term>
+        <listitem>
+          <para>
+	    List the contents of one or more metadata blocks to stdout.  By
+	    default, all metadata blocks are listed in text format.  Use the
+	    following options to change this behavior:
+	  </para>
+	  <variablelist>
+	    <varlistentry>
+	      <term><option>--block-number=#[,#[...]]</option></term>
+	      <listitem>
+		<para>
+		  An optional comma-separated list of block numbers to display.
+		  The first block, the STREAMINFO block, is block 0.
+		</para>
+	      </listitem>
+	    </varlistentry>
+	    <varlistentry>
+	      <term><option>--block-type=type[,type[...]]</option></term>
+	      <listitem><para></para></listitem>
+	    </varlistentry>
+	    <varlistentry>
+	      <term><option>--except-block-type=type[,type[...]]</option></term>
+	      <listitem>
+		<para>
+		  An optional comma-separated list of block types to be included
+		  or ignored with this option.  Use only one of --block-type or
+		  --except-block-type.  The valid block types are: STREAMINFO,
+		  PADDING, APPLICATION, SEEKTABLE, VORBIS_COMMENT, PICTURE.  You
+		  may narrow down the types of APPLICATION blocks displayed as
+		  follows:
+		</para>
+		<para>
+        APPLICATION:abcd        The APPLICATION block(s) whose textual repre-
+                                sentation of the 4-byte ID is "abcd"
+        APPLICATION:0xXXXXXXXX  The APPLICATION block(s) whose hexadecimal big-
+                                endian representation of the 4-byte ID is
+                                "0xXXXXXXXX".  For the example "abcd" above the
+                                hexadecimal equivalalent is 0x61626364
+		</para>
+		<note>
+		  <para>
+		    if both --block-number and --[except-]block-type are
+		    specified, the result is the logical AND of both
+		    arguments.</para></note>
+	      </listitem>
+	    </varlistentry>
+	    <varlistentry>
+	      <term><option>--application-data-format=hexdump|text</option></term>
+	      <listitem>
+		<para>
+		  If the application block you are displaying contains binary
+		  data but your --data-format=text, you can display a hex dump
+		  of the application data contents instead using
+		  --application-data-format=hexdump.
+		</para>
+	      </listitem>
+	    </varlistentry>
+	  </variablelist>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove</option></term>
+        <listitem>
+          <para>
+            Remove one or more metadata blocks from the metadata.  Unless
+            --dont-use-padding is specified, the blocks will be replaced with
+            padding.  You may not remove the STREAMINFO block.
+	  </para>
+	  <variablelist>
+	    <varlistentry>
+	      <term><option>--block-number=#[,#[...]]</option></term>
+	      <listitem><para></para></listitem>
+	    </varlistentry>
+	    <varlistentry>
+	      <term><option>--block-type=type[,type[...]]</option></term>
+	      <listitem><para></para></listitem>
+	    </varlistentry>
+	    <varlistentry>
+	      <term><option>--except-block-type=type[,type[...]]</option></term>
+	      <listitem>
+		<para>See --list above for usage.</para>
+		<note>
+		  <para>
+		    if both --block-number and --[except-]block-type are
+		    specified, the result is the logical AND of both arguments.
+		  </para></note>
+	      </listitem>
+	    </varlistentry>
+	  </variablelist>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove-all</option></term>
+        <listitem>
+          <para>
+            Remove all metadata blocks (except the STREAMINFO block) from the
+            metadata.  Unless --dont-use-padding is specified, the blocks will
+            be replaced with padding.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--merge-padding</option></term>
+        <listitem>
+          <para>
+	    Merge adjacent PADDING blocks into single blocks.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--sort-padding</option></term>
+        <listitem>
+          <para>
+	    Move all PADDING blocks to the end of the metadata and merge them
+            into a single block.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para>flac(1).</para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/microbench/CMakeLists.txt b/microbench/CMakeLists.txt
new file mode 100644
index 0000000..639915b
--- /dev/null
+++ b/microbench/CMakeLists.txt
@@ -0,0 +1,17 @@
+if(MSVC)
+    return()
+endif()
+
+set(CMAKE_REQUIRED_LIBRARIES rt)
+check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
+
+if(APPLE)
+    add_definitions(-DFLAC__SYS_DARWIN)
+endif()
+
+add_executable(benchmark_residual benchmark_residual.c util.c)
+target_include_directories(benchmark_residual PRIVATE
+    "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/include")
+target_link_libraries(benchmark_residual
+    FLAC
+    $<$<BOOL:${HAVE_CLOCK_GETTIME}>:rt>)
diff --git a/microbench/Makefile.am b/microbench/Makefile.am
new file mode 100644
index 0000000..8bad781
--- /dev/null
+++ b/microbench/Makefile.am
@@ -0,0 +1,42 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2015-2016  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.
+
+
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/libFLAC/include
+
+noinst_HEADERS = util.h
+
+noinst_PROGRAMS = benchmark_residual
+
+benchmark_residual_SOURCES = benchmark_residual.c util.c
+
+benchmark_residual_LDADD = @LIB_CLOCK_GETTIME@
+
+EXTRA_DIST = CMakeLists.txt
diff --git a/microbench/benchmark_residual.c b/microbench/benchmark_residual.c
new file mode 100644
index 0000000..588c05b
--- /dev/null
+++ b/microbench/benchmark_residual.c
@@ -0,0 +1,151 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 <stdio.h>
+#include <math.h>
+#include <string.h>
+#include "FLAC/ordinals.h"
+#include "share/compat.h"
+#include "private/bitmath.h"
+#include "private/fixed.h"
+#include "private/macros.h"
+#include "FLAC/assert.h"
+
+#include "util.h"
+
+static void FLAC__fixed_compute_residual_shift(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[])
+{
+	const int idata_len = (int) data_len;
+	int i;
+
+	switch(order) {
+		case 0:
+			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++)
+				residual[i] = data[i] - data[i-1];
+			break;
+		case 2:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - (data[i-1] << 1) + data[i-2];
+			break;
+		case 3:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3];
+			break;
+		case 4:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4];
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+}
+
+static void FLAC__fixed_compute_residual_mult(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[])
+{
+	const int idata_len = (int)data_len;
+	int i;
+
+	switch(order) {
+		case 0:
+			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++)
+				residual[i] = data[i] - data[i-1];
+			break;
+		case 2:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 2*data[i-1] + data[i-2];
+			break;
+		case 3:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+			break;
+		case 4:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+}
+
+static FLAC__int32 data [200000] ;
+static FLAC__int32 residual [200000] ;
+
+static unsigned bench_order = 0 ;
+
+static void
+bench_shift (void)
+{	FLAC__fixed_compute_residual_shift (data, ARRAY_LEN (data), bench_order, residual) ;
+}
+
+static void
+bench_mult (void)
+{	FLAC__fixed_compute_residual_mult (data, ARRAY_LEN (data), bench_order, residual) ;
+}
+
+int
+main (void)
+{	bench_stats	stats ;
+
+	puts ("") ;
+
+	for (bench_order = 2 ; bench_order <= 4 ; bench_order ++) {
+		memset (&stats, 0, sizeof (stats)) ;
+		stats.testfunc = bench_shift ;
+		stats.run_count = 100 ;
+		stats.loop_count = 10 ;
+
+		benchmark_stats (&stats) ;
+		printf ("shift order %u : %f %f %f %f\n", bench_order, stats.min_time, stats.median_time, stats.mean_time, stats.max_time) ;
+
+		memset (&stats, 0, sizeof (stats)) ;
+		stats.testfunc = bench_mult ;
+		stats.run_count = 100 ;
+		stats.loop_count = 10 ;
+
+		benchmark_stats (&stats) ;
+		printf ("mult  order %u : %f %f %f %f\n\n", bench_order, stats.min_time, stats.median_time, stats.mean_time, stats.max_time) ;
+	}
+
+	return 0 ;
+}
diff --git a/microbench/util.c b/microbench/util.c
new file mode 100644
index 0000000..66003d7
--- /dev/null
+++ b/microbench/util.c
@@ -0,0 +1,205 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2015-2016  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 "util.h"
+
+#if defined _WIN32
+
+#include <windows.h>
+
+static double
+counter_diff (const LARGE_INTEGER * start, const LARGE_INTEGER * end)
+{
+	LARGE_INTEGER diff, freq;
+
+	QueryPerformanceFrequency(&freq);
+	diff.QuadPart = end->QuadPart - start->QuadPart;
+
+	return (double)diff.QuadPart/(double)freq.QuadPart;
+}
+
+double
+benchmark_function (void (*testfunc) (void), unsigned count)
+{
+	LARGE_INTEGER start, end;
+	unsigned k;
+
+	QueryPerformanceCounter (&start) ;
+
+	for (k = 0 ; k < count ; k++)
+		testfunc();
+
+	QueryPerformanceCounter (&end) ;
+
+	return counter_diff (&start, &end) / count ;
+} /* benchmark_function */
+
+#elif defined FLAC__SYS_DARWIN
+
+#include <mach/mach_time.h>
+
+static double
+counter_diff (const uint64_t * start, const uint64_t * end)
+{
+	mach_timebase_info_data_t t_info;
+	mach_timebase_info(&t_info);
+	uint64_t duration = *end - *start;
+
+	return duration * ((double)t_info.numer/(double)t_info.denom);
+}
+
+double
+benchmark_function (void (*testfunc) (void), unsigned count)
+{
+	uint64_t start, end;
+	unsigned k;
+
+	start = mach_absolute_time();
+
+	for (k = 0 ; k < count ; k++)
+		testfunc();
+
+	end = mach_absolute_time();
+
+	return counter_diff (&start, &end) / count ;
+} /* benchmark_function */
+
+#elif defined HAVE_CLOCK_GETTIME
+
+#include <time.h>
+#include <sys/time.h>
+
+static double
+timespec_diff (const struct timespec * start, const struct timespec * end)
+{	struct timespec diff;
+
+	if (end->tv_nsec - start->tv_nsec < 0)
+	{	diff.tv_sec = end->tv_sec - start->tv_sec - 1 ;
+		diff.tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec ;
+		}
+	else
+	{	diff.tv_sec = end->tv_sec - start->tv_sec ;
+		diff.tv_nsec = end->tv_nsec-start->tv_nsec ;
+		} ;
+
+	return diff.tv_sec + 1e-9 * diff.tv_nsec ;
+}
+
+double
+benchmark_function (void (*testfunc) (void), unsigned count)
+{	struct timespec start, end;
+	unsigned k ;
+
+	clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &start) ;
+
+	for (k = 0 ; k < count ; k++)
+		testfunc () ;
+
+	clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &end) ;
+
+	return timespec_diff (&start, &end) / count ;
+} /* benchmark_function */
+
+#else
+
+#include <time.h>
+#include <sys/time.h>
+
+static double
+timeval_diff (const struct timeval * start, const struct timeval * end)
+{       struct timeval diff;
+
+        if (end->tv_usec - start->tv_usec < 0)
+        {       diff.tv_sec = end->tv_sec - start->tv_sec - 1 ;
+                diff.tv_usec = 1000000 + end->tv_usec - start->tv_usec ;
+                }
+        else
+        {       diff.tv_sec = end->tv_sec - start->tv_sec ;
+                diff.tv_usec = end->tv_usec-start->tv_usec ;
+                } ;
+
+        return diff.tv_sec + 1e-6 * diff.tv_usec ;
+}
+
+double
+benchmark_function (void (*testfunc) (void), unsigned count)
+{	struct timeval start, end;
+	unsigned k ;
+
+	gettimeofday(&start, NULL);
+
+	for (k = 0 ; k < count ; k++)
+		testfunc () ;
+
+	gettimeofday(&end, NULL);
+
+	return timeval_diff (&start, &end) / count ;
+} /* benchmark_function */
+
+#endif
+
+static int
+double_cmp (const void * a, const void * b)
+{	const double * pa = (double *) a ;
+	const double * pb = (double *) b ;
+	return pa [0] < pb [0] ;
+} /* double_cmp */
+
+void
+benchmark_stats (bench_stats * stats)
+{	double sum, times [stats->run_count] ;
+	unsigned k ;
+
+	for (k = 0 ; k < stats->run_count ; k++)
+		times [k] = benchmark_function (stats->testfunc, stats->loop_count) ;
+
+	qsort (times, stats->run_count, sizeof (times [0]), double_cmp) ;
+
+	sum = 0.0 ;
+	stats->min_time = stats->max_time = times [0] ;
+	for (k = 0 ; k < stats->run_count ; k++)
+	{	stats->min_time = stats->min_time < times [k] ? stats->min_time : times [k] ;
+		stats->max_time = stats->max_time > times [k] ? stats->max_time : times [k] ;
+		sum += times [k] ;
+		}
+	stats->mean_time = sum / stats->run_count ;
+	if (stats->run_count & 1)
+		stats->median_time = times [(stats->run_count + 1) / 2] ;
+	else
+		stats->median_time = 0.5 * (times [stats->run_count / 2] + times [(stats->run_count / 2) + 1]) ;
+
+	return ;
+} /* benchmark_stats */
diff --git a/microbench/util.h b/microbench/util.h
new file mode 100644
index 0000000..db0ee75
--- /dev/null
+++ b/microbench/util.h
@@ -0,0 +1,43 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2015-2016  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.
+ */
+
+#define ARRAY_LEN(x) 	((sizeof (x) / sizeof (x [0])))
+
+typedef struct bench_stats
+{	void (*testfunc) (void) ;
+	unsigned run_count ;
+	unsigned loop_count ;
+	double min_time, mean_time, median_time, max_time ;
+} bench_stats ;
+
+double benchmark_function (void (*testfunc) (void), unsigned count) ;
+
+void benchmark_stats (bench_stats * stats) ;
diff --git a/oss-fuzz/Makefile.am b/oss-fuzz/Makefile.am
new file mode 100644
index 0000000..7c4e2f6
--- /dev/null
+++ b/oss-fuzz/Makefile.am
@@ -0,0 +1,62 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2019  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/oss-fuzz
+
+AM_CXXFLAGS = -std=c++11
+
+EXTRA_DIST = \
+	fuzz-encoder.dict \
+	fuzzing/Readme.md \
+	fuzzing/datasource/datasource.hpp \
+	fuzzing/datasource/id.hpp \
+	fuzzing/exception.hpp \
+	fuzzing/memory.hpp \
+	fuzzing/types.hpp
+
+if USE_OSSFUZZ_FLAG
+FUZZ_FLAG = $(LIB_FUZZING_ENGINE)
+FUZZ_LDADD = -lFuzzer
+else
+if USE_OSSFUZZ_STATIC
+FUZZ_LDADD = $(LIB_FUZZING_ENGINE)
+FUZZ_FLAG = -lFuzzer
+endif
+endif
+
+noinst_PROGRAMS =
+
+if USE_OSSFUZZERS
+noinst_PROGRAMS += fuzz-decoder fuzz-encoder
+endif
+
+fuzz_decoder_SOURCES = fuzz-decoder.cc
+fuzz_decoder_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG)
+fuzz_decoder_LDFLAGS = $(AM_LDFLAGS) -static
+fuzz_decoder_LDADD = $(flac_libs) $(FUZZ_LDADD)
+
+fuzz_encoder_SOURCES = fuzz-encoder.cc
+fuzz_encoder_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG)
+fuzz_encoder_LDFLAGS = $(AM_LDFLAGS) -static
+fuzz_encoder_LDADD = $(flac_libs) $(FUZZ_LDADD)
+
+flac_libs = \
+	$(top_builddir)/src/libFLAC/libFLAC-static.la \
+	$(top_builddir)/src/libFLAC++/libFLAC++-static.la \
+	@OGG_LIBS@ \
+	-lm
+
diff --git a/oss-fuzz/fuzz-decoder.cc b/oss-fuzz/fuzz-decoder.cc
new file mode 100644
index 0000000..b273387
--- /dev/null
+++ b/oss-fuzz/fuzz-decoder.cc
@@ -0,0 +1,355 @@
+#include <cstddef>
+#include <cstdint>
+
+#include <fuzzing/datasource/datasource.hpp>
+#include <fuzzing/memory.hpp>
+
+#include "FLAC++/decoder.h"
+
+template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) {
+    (void)id;
+    switch ( Get<uint8_t>() ) {
+        case 0:
+            return FLAC__METADATA_TYPE_STREAMINFO;
+        case 1:
+            return FLAC__METADATA_TYPE_PADDING;
+        case 2:
+            return FLAC__METADATA_TYPE_APPLICATION;
+        case 3:
+            return FLAC__METADATA_TYPE_SEEKTABLE;
+        case 4:
+            return FLAC__METADATA_TYPE_VORBIS_COMMENT;
+        case 5:
+            return FLAC__METADATA_TYPE_CUESHEET;
+        case 6:
+            return FLAC__METADATA_TYPE_PICTURE;
+        case 7:
+            return FLAC__METADATA_TYPE_UNDEFINED;
+        case 8:
+            return FLAC__MAX_METADATA_TYPE;
+        default:
+            return FLAC__METADATA_TYPE_STREAMINFO;
+    }
+}
+
+namespace FLAC {
+	namespace Decoder {
+        class FuzzerStream : public Stream {
+            private:
+                fuzzing::datasource::Datasource& ds;
+            public:
+                FuzzerStream(fuzzing::datasource::Datasource& dsrc) :
+                    Stream(), ds(dsrc) { }
+
+                ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)  override {
+                    try {
+                        const size_t maxCopySize = *bytes;
+
+                        if ( maxCopySize > 0 ) {
+                            /* memset just to test if this overwrites anything, and triggers ASAN */
+                            memset(buffer, 0, maxCopySize);
+                        }
+
+                        const auto data = ds.GetData(0);
+                        const auto dataSize = data.size();
+                        const auto copySize = std::min(maxCopySize, dataSize);
+
+                        if ( copySize > 0 ) {
+                            memcpy(buffer, data.data(), copySize);
+                        }
+
+                        *bytes = copySize;
+
+                        return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+                    } catch ( ... ) {
+	                    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+                    }
+                }
+
+                ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])  override {
+                    {
+                        fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header));
+                        fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer));
+                    }
+
+                    {
+                        const auto numChannels = get_channels();
+                        const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32);
+                        for (size_t i = 0; i < numChannels; i++) {
+                            fuzzing::memory::memory_test(buffer[i], bytesPerChannel);
+                        }
+                    }
+
+                    try {
+                        if ( ds.Get<bool>() == true ) {
+	                        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+                        }
+                    } catch ( ... ) { }
+                    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+                }
+
+                void error_callback(::FLAC__StreamDecoderErrorStatus status)  override {
+                    fuzzing::memory::memory_test(status);
+                }
+
+                void metadata_callback(const ::FLAC__StreamMetadata *metadata) override {
+                    fuzzing::memory::memory_test(metadata->type);
+                    fuzzing::memory::memory_test(metadata->is_last);
+                    fuzzing::memory::memory_test(metadata->length);
+                    fuzzing::memory::memory_test(metadata->data);
+                }
+
+                ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override {
+                    fuzzing::memory::memory_test(absolute_byte_offset);
+
+                    try {
+                        if ( ds.Get<bool>() == true ) {
+                            return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+                        } else {
+                            return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+                        }
+                    } catch ( ... ) {
+                        return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+                    }
+                }
+#if 0
+                ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) override {
+                    fuzzing::memory::memory_test(*absolute_byte_offset);
+
+                    try {
+                        if ( ds.Get<bool>() == true ) {
+                            return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+                        } else {
+                            return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+                        }
+                    } catch ( ... ) {
+                        return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+                    }
+                }
+
+                ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) override {
+                    fuzzing::memory::memory_test(*stream_length);
+
+                    try {
+                        if ( ds.Get<bool>() == true ) {
+                            return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+                        } else {
+                            return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+                        }
+                    } catch ( ... ) {
+                        return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+                    }
+                }
+#endif
+        };
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    fuzzing::datasource::Datasource ds(data, size);
+    FLAC::Decoder::FuzzerStream decoder(ds);
+
+    try {
+        {
+            ::FLAC__StreamDecoderInitStatus ret;
+
+            if ( ds.Get<bool>() ) {
+                ret = decoder.init();
+            } else {
+                ret = decoder.init_ogg();
+            }
+
+            if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
+                goto end;
+            }
+        }
+
+        if ( ds.Get<bool>() ) {
+#ifdef FUZZER_DEBUG
+            printf("set_ogg_serial_number\n");
+#endif
+            decoder.set_ogg_serial_number(ds.Get<long>());
+        }
+        if ( ds.Get<bool>() ) {
+#ifdef FUZZER_DEBUG
+            printf("set_md5_checking\n");
+#endif
+            decoder.set_md5_checking(ds.Get<bool>());
+        }
+        if ( ds.Get<bool>() ) {
+#ifdef FUZZER_DEBUG
+            printf("set_metadata_respond\n");
+#endif
+            decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>());
+        }
+        if ( ds.Get<bool>() ) {
+            const auto idVector = ds.GetData(0);
+            unsigned char id[4];
+            if ( idVector.size() >= sizeof(id) ) {
+                memcpy(id, idVector.data(), sizeof(id));
+#ifdef FUZZER_DEBUG
+                printf("set_metadata_respond_application\n");
+#endif
+                decoder.set_metadata_respond_application(id);
+            }
+        }
+        if ( ds.Get<bool>() ) {
+#ifdef FUZZER_DEBUG
+            printf("set_metadata_respond_all\n");
+#endif
+            decoder.set_metadata_respond_all();
+        }
+        if ( ds.Get<bool>() ) {
+#ifdef FUZZER_DEBUG
+            printf("set_metadata_ignore\n");
+#endif
+            decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>());
+        }
+        if ( ds.Get<bool>() ) {
+            const auto idVector = ds.GetData(0);
+            unsigned char id[4];
+            if ( idVector.size() >= sizeof(id) ) {
+                memcpy(id, idVector.data(), sizeof(id));
+#ifdef FUZZER_DEBUG
+                printf("set_metadata_ignore_application\n");
+#endif
+                decoder.set_metadata_ignore_application(id);
+            }
+        }
+        if ( ds.Get<bool>() ) {
+#ifdef FUZZER_DEBUG
+            printf("set_metadata_ignore_all\n");
+#endif
+            decoder.set_metadata_ignore_all();
+        }
+
+        while ( ds.Get<bool>() ) {
+            switch ( ds.Get<uint8_t>() ) {
+                case    0:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("flush\n");
+#endif
+                        const bool res = decoder.flush();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    1:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("reset\n");
+#endif
+                        const bool res = decoder.reset();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    2:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("process_single\n");
+#endif
+                        const bool res = decoder.process_single();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    3:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("process_until_end_of_metadata\n");
+#endif
+                        const bool res = decoder.process_until_end_of_metadata();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    4:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("process_until_end_of_stream\n");
+#endif
+                        const bool res = decoder.process_until_end_of_stream();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    5:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("skip_single_frame\n");
+#endif
+                        const bool res = decoder.skip_single_frame();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    6:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("seek_absolute\n");
+#endif
+                        const bool res = decoder.seek_absolute(ds.Get<uint64_t>());
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    7:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("get_md5_checking\n");
+#endif
+                        const bool res = decoder.get_md5_checking();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    8:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("get_total_samples\n");
+#endif
+                        const bool res = decoder.get_total_samples();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    9:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("get_channels\n");
+#endif
+                        const bool res = decoder.get_channels();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    10:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("get_bits_per_sample\n");
+#endif
+                        const bool res = decoder.get_bits_per_sample();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    11:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("get_sample_rate\n");
+#endif
+                        const bool res = decoder.get_sample_rate();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+                case    12:
+                    {
+#ifdef FUZZER_DEBUG
+                        printf("get_blocksize\n");
+#endif
+                        const bool res = decoder.get_blocksize();
+                        fuzzing::memory::memory_test(res);
+                    }
+                    break;
+            }
+        }
+    } catch ( ... ) { }
+
+end:
+    {
+        const bool res = decoder.finish();
+        fuzzing::memory::memory_test(res);
+    }
+    return 0;
+}
diff --git a/oss-fuzz/fuzz-encoder.cc b/oss-fuzz/fuzz-encoder.cc
new file mode 100644
index 0000000..067af05
--- /dev/null
+++ b/oss-fuzz/fuzz-encoder.cc
@@ -0,0 +1,154 @@
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+
+#include <fuzzing/datasource/datasource.hpp>
+#include <fuzzing/memory.hpp>
+
+#include "FLAC++/encoder.h"
+
+#define SAMPLE_VALUE_LIMIT (1024*1024*10)
+
+static_assert(SAMPLE_VALUE_LIMIT <= std::numeric_limits<FLAC__int32>::max(), "Invalid SAMPLE_VALUE_LIMIT");
+static_assert(-SAMPLE_VALUE_LIMIT >= std::numeric_limits<FLAC__int32>::min(), "Invalid SAMPLE_VALUE_LIMIT");
+
+namespace FLAC {
+	namespace Encoder {
+        class FuzzerStream : public Stream {
+            private:
+                // fuzzing::datasource::Datasource& ds;
+            public:
+                FuzzerStream(fuzzing::datasource::Datasource&) :
+                    Stream() { }
+
+                ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override {
+                    fuzzing::memory::memory_test(buffer, bytes);
+#if 0
+                    try {
+                        if ( ds.Get<bool>() == true ) {
+	                        return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+                        }
+                    } catch ( ... ) { }
+#endif
+                    return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+                }
+        };
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    fuzzing::datasource::Datasource ds(data, size);
+    FLAC::Encoder::FuzzerStream encoder(ds);
+
+    const int channels = 2;
+	encoder.set_channels(channels);
+	encoder.set_bits_per_sample(16);
+
+    try {
+        ::FLAC__StreamEncoderInitStatus ret;
+
+        if ( ds.Get<bool>() ) {
+            ret = encoder.init();
+        } else {
+            ret = encoder.init_ogg();
+        }
+
+        if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) {
+            goto end;
+        }
+
+        {
+            const bool res = encoder.set_streamable_subset(ds.Get<bool>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_ogg_serial_number(ds.Get<long>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_verify(ds.Get<bool>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_compression_level(ds.Get<uint8_t>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_do_exhaustive_model_search(ds.Get<bool>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_do_mid_side_stereo(ds.Get<bool>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_loose_mid_side_stereo(ds.Get<bool>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const auto s = ds.Get<std::string>();
+            const bool res = encoder.set_apodization(s.data());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_max_lpc_order(ds.Get<uint8_t>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_qlp_coeff_precision(ds.Get<uint32_t>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_do_qlp_coeff_prec_search(ds.Get<bool>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_do_escape_coding(ds.Get<bool>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_min_residual_partition_order(ds.Get<uint32_t>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_max_residual_partition_order(ds.Get<uint32_t>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_rice_parameter_search_dist(ds.Get<uint32_t>());
+            fuzzing::memory::memory_test(res);
+        }
+        {
+            const bool res = encoder.set_total_samples_estimate(ds.Get<uint64_t>());
+            fuzzing::memory::memory_test(res);
+        }
+
+        while ( ds.Get<bool>() ) {
+            {
+                auto dat = ds.GetVector<FLAC__int32>();
+                for (size_t i = 0; i < dat.size(); i++) {
+                    if ( SAMPLE_VALUE_LIMIT != 0 ) {
+                        if ( dat[i] < -SAMPLE_VALUE_LIMIT ) {
+                            dat[i] = -SAMPLE_VALUE_LIMIT;
+                        } else if ( dat[i] > SAMPLE_VALUE_LIMIT ) {
+                            dat[i] = SAMPLE_VALUE_LIMIT;
+                        }
+                    }
+                }
+                const uint32_t samples = dat.size() / 2;
+                if ( samples > 0 ) {
+                    const int32_t* ptr = dat.data();
+                    const bool res = encoder.process_interleaved(ptr, samples);
+                    fuzzing::memory::memory_test(res);
+                }
+            }
+        }
+    } catch ( ... ) { }
+
+end:
+    {
+        const bool res = encoder.finish();
+        fuzzing::memory::memory_test(res);
+    }
+    return 0;
+}
diff --git a/oss-fuzz/fuzz-encoder.dict b/oss-fuzz/fuzz-encoder.dict
new file mode 100644
index 0000000..fe5b77f
--- /dev/null
+++ b/oss-fuzz/fuzz-encoder.dict
@@ -0,0 +1,17 @@
+"bartlett"
+"bartlett_hann"
+"blackman"
+"blackman_harris_4term_92db"
+"connes"
+"flattop"
+"gauss()"
+"hamming"
+"hann"
+"kaiser_bessel"
+"nuttall"
+"rectangle"
+"triangle"
+"tukey(0)"
+"partial_tukey(0)"
+"punchout_tukey(0)"
+"welch"
diff --git a/oss-fuzz/fuzzing/Readme.md b/oss-fuzz/fuzzing/Readme.md
new file mode 100644
index 0000000..d2fbd68
--- /dev/null
+++ b/oss-fuzz/fuzzing/Readme.md
@@ -0,0 +1,6 @@
+The header files in this directory and below were taken from:
+
+    https://github.com/guidovranken/fuzzing-headers.git
+
+Some minor modifications were made to make them build with the default C++
+warning flags.
diff --git a/oss-fuzz/fuzzing/datasource/datasource.hpp b/oss-fuzz/fuzzing/datasource/datasource.hpp
new file mode 100644
index 0000000..09fa8db
--- /dev/null
+++ b/oss-fuzz/fuzzing/datasource/datasource.hpp
@@ -0,0 +1,167 @@
+#pragma once
+
+#include <fuzzing/exception.hpp>
+#include <fuzzing/types.hpp>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace fuzzing {
+namespace datasource  {
+
+class Base
+{
+    protected:
+        virtual std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) = 0;
+    public:
+        Base(void) = default;
+        virtual ~Base(void) = default;
+
+        template<class T> T Get(const uint64_t id = 0);
+        uint16_t GetChoice(const uint64_t id = 0);
+        std::vector<uint8_t> GetData(const uint64_t id, const size_t min = 0, const size_t max = 0);
+        template <class T> std::vector<T> GetVector(const uint64_t id = 0);
+
+        class OutOfData : public fuzzing::exception::FlowException {
+            public:
+                OutOfData() = default;
+        };
+
+        class DeserializationFailure : public fuzzing::exception::FlowException {
+            public:
+                DeserializationFailure() = default;
+        };
+};
+
+#ifndef FUZZING_HEADERS_NO_IMPL
+template<class T> T Base::Get(const uint64_t id)
+{
+    T ret;
+    const auto v = get(sizeof(ret), sizeof(ret), id);
+    memcpy(&ret, v.data(), sizeof(ret));
+    return ret;
+}
+
+template <> bool Base::Get<bool>(const uint64_t id)
+{
+    uint8_t ret;
+    const auto v = get(sizeof(ret), sizeof(ret), id);
+    memcpy(&ret, v.data(), sizeof(ret));
+    return (ret % 2) ? true : false;
+}
+
+template <> std::string Base::Get<std::string>(const uint64_t id)
+{
+    auto data = GetData(id);
+    return std::string(data.data(), data.data() + data.size());
+}
+
+template <> std::vector<std::string> Base::Get<std::vector<std::string>>(const uint64_t id)
+{
+    std::vector<std::string> ret;
+    while ( true ) {
+        auto data = GetData(id);
+        ret.push_back( std::string(data.data(), data.data() + data.size()) );
+        if ( Get<bool>(id) == false ) {
+            break;
+        }
+    }
+    return ret;
+}
+
+uint16_t Base::GetChoice(const uint64_t id)
+{
+    return Get<uint16_t>(id);
+}
+
+std::vector<uint8_t> Base::GetData(const uint64_t id, const size_t min, const size_t max)
+{
+    return get(min, max, id);
+}
+
+
+template <> types::String<> Base::Get<types::String<>>(const uint64_t id) {
+    const auto data = GetData(id);
+    types::String<> ret(data.data(), data.size());
+    return ret;
+}
+
+template <> types::Data<> Base::Get<types::Data<>>(const uint64_t id) {
+    const auto data = GetData(id);
+    types::Data<> ret(data.data(), data.size());
+    return ret;
+}
+
+template <class T>
+std::vector<T> Base::GetVector(const uint64_t id) {
+    std::vector<T> ret;
+
+    while ( Get<bool>(id) == true ) {
+        ret.push_back( Get<T>(id) );
+    }
+
+    return ret;
+}
+#endif
+
+class Datasource : public Base
+{
+    private:
+        const uint8_t* data;
+        const size_t size;
+        size_t idx;
+        size_t left;
+        std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) override;
+
+		// Make copy constructor and assignment operator private.
+        Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {}
+        Datasource& operator=(const Datasource &) { return *this; }
+    public:
+        Datasource(const uint8_t* _data, const size_t _size);
+};
+
+#ifndef FUZZING_HEADERS_NO_IMPL
+Datasource::Datasource(const uint8_t* _data, const size_t _size) :
+    Base(), data(_data), size(_size), idx(0), left(size)
+{
+}
+
+std::vector<uint8_t> Datasource::get(const size_t min, const size_t max, const uint64_t id) {
+    (void)id;
+
+    uint32_t getSize;
+    if ( left < sizeof(getSize) ) {
+        throw OutOfData();
+    }
+    memcpy(&getSize, data + idx, sizeof(getSize));
+    idx += sizeof(getSize);
+    left -= sizeof(getSize);
+
+    if ( getSize < min ) {
+        getSize = min;
+    }
+    if ( max && getSize > max ) {
+        getSize = max;
+    }
+
+    if ( left < getSize ) {
+        throw OutOfData();
+    }
+
+    std::vector<uint8_t> ret(getSize);
+
+    if ( getSize > 0 ) {
+        memcpy(ret.data(), data + idx, getSize);
+    }
+    idx += getSize;
+    left -= getSize;
+
+    return ret;
+}
+#endif
+
+} /* namespace datasource */
+} /* namespace fuzzing */
diff --git a/oss-fuzz/fuzzing/datasource/id.hpp b/oss-fuzz/fuzzing/datasource/id.hpp
new file mode 100644
index 0000000..3ba38d7
--- /dev/null
+++ b/oss-fuzz/fuzzing/datasource/id.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <stdio.h>
+#include <stdint.h>
+#include <utility>
+#include <map>
+
+namespace fuzzing {
+namespace datasource  {
+
+/* From: https://gist.github.com/underscorediscovery/81308642d0325fd386237cfa3b44785c */
+inline uint64_t hash_64_fnv1a(const void* key, const uint64_t len) {
+
+    const char* data = (char*)key;
+    uint64_t hash = 0xcbf29ce484222325;
+    uint64_t prime = 0x100000001b3;
+
+    for(uint64_t i = 0; i < len; ++i) {
+        uint8_t value = data[i];
+        hash = hash ^ value;
+        hash *= prime;
+    }
+
+    return hash;
+
+} //hash_64_fnv1a
+
+// FNV1a c++11 constexpr compile time hash functions, 32 and 64 bit
+// str should be a null terminated string literal, value should be left out 
+// e.g hash_32_fnv1a_const("example")
+// code license: public domain or equivalent
+// post: https://notes.underscorediscovery.com/constexpr-fnv1a/
+
+constexpr uint32_t val_32_const = 0x811c9dc5;
+constexpr uint32_t prime_32_const = 0x1000193;
+constexpr uint64_t val_64_const = 0xcbf29ce484222325;
+constexpr uint64_t prime_64_const = 0x100000001b3;
+
+
+inline constexpr uint64_t ID(const char* const str, const uint64_t value = val_64_const) noexcept {
+    auto ret = (str[0] == '\0') ? value : ID(&str[1], (value ^ uint64_t(str[0])) * prime_64_const);
+    return ret;
+}
+
+inline constexpr std::pair<const char*, uint64_t> IDPair(const char* const str, const uint64_t value = val_64_const) noexcept {
+    return {str, ID(str, value)};
+}
+
+using IDMap = std::map<const char*, uint64_t>;
+
+} /* namespace datasource */
+} /* namespace fuzzing */
diff --git a/oss-fuzz/fuzzing/exception.hpp b/oss-fuzz/fuzzing/exception.hpp
new file mode 100644
index 0000000..55c360d
--- /dev/null
+++ b/oss-fuzz/fuzzing/exception.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <exception>
+#include <string>
+
+namespace fuzzing {
+namespace exception {
+
+class ExceptionBase : public std::exception {
+    public:
+        ExceptionBase(void) = default;
+        /* typeid(T).name */
+};
+
+/* Recoverable exception */
+class FlowException : public ExceptionBase {
+    public:
+        FlowException(void) : ExceptionBase() { }
+};
+
+/* Error in this library, should never happen */
+class LogicException : public ExceptionBase {
+    private:
+        std::string reason;
+    public:
+        LogicException(const std::string r) : ExceptionBase(), reason(r) { }
+        virtual const char* what(void) const throw() {
+            return reason.c_str();
+        }
+};
+
+/* Error in target application */
+class TargetException : public ExceptionBase {
+    private:
+        std::string reason;
+    public:
+        TargetException(const std::string r) : ExceptionBase(), reason(r) { }
+        virtual const char* what(void) const throw() {
+            return reason.c_str();
+        }
+};
+
+} /* namespace exception */
+} /* namespace fuzzing */
diff --git a/oss-fuzz/fuzzing/memory.hpp b/oss-fuzz/fuzzing/memory.hpp
new file mode 100644
index 0000000..804e23b
--- /dev/null
+++ b/oss-fuzz/fuzzing/memory.hpp
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <stdio.h>
+#include <optional>
+
+#ifndef ASAN
+#define ASAN 0
+#endif
+
+#ifndef MSAN
+#define MSAN 0
+#endif
+
+namespace fuzzing {
+namespace memory {
+
+#ifndef FUZZING_HEADERS_NO_IMPL
+#if ASAN == 1
+extern "C" void *__asan_region_is_poisoned(const void *beg, size_t size);
+#endif
+
+#if MSAN == 1
+extern "C" void __msan_check_mem_is_initialized(const volatile void *x, size_t size);
+#endif
+
+void memory_test_asan(const void* data, const size_t size)
+{
+    (void)data;
+    (void)size;
+
+#if ASAN == 1
+    if ( __asan_region_is_poisoned(data, size) != NULL ) {
+        abort();
+    }
+#endif
+}
+
+void memory_test_msan(const void* data, const size_t size)
+{
+    (void)data;
+    (void)size;
+
+#if MSAN == 1
+    __msan_check_mem_is_initialized(data, size);
+#endif
+}
+
+void memory_test(const void* data, const size_t size)
+{
+    memory_test_asan(data, size);
+    memory_test_msan(data, size);
+}
+
+template <class T>
+void memory_test(const T& t)
+{
+    (void)t;
+}
+
+template <>
+void memory_test(const std::string& s)
+{
+    (void)s;
+
+#if MSAN == 1
+    memory_test(s.data(), s.size());
+#endif
+}
+
+#endif
+
+} /* namespace memory */
+} /* namespace fuzzing */
diff --git a/oss-fuzz/fuzzing/types.hpp b/oss-fuzz/fuzzing/types.hpp
new file mode 100644
index 0000000..f2b56fc
--- /dev/null
+++ b/oss-fuzz/fuzzing/types.hpp
@@ -0,0 +1,135 @@
+#pragma once
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <fuzzing/memory.hpp>
+#include <vector>
+#include <string>
+
+namespace fuzzing {
+namespace types {
+
+template <typename CoreType, bool NullTerminated, bool UseMSAN = false>
+class Container {
+    private:
+        CoreType* InvalidAddress = (CoreType*)0x12;
+
+        CoreType* _data = InvalidAddress;
+        size_t _size = 0;
+
+#ifndef FUZZING_HEADERS_NO_IMPL
+        void copy(const void* data, size_t size) {
+            if ( size > 0 ) {
+                std::memcpy(_data, data, size);
+            }
+        }
+
+        void allocate(size_t size) {
+            if ( size > 0 ) {
+                _data = static_cast<CoreType*>(malloc(size * sizeof(CoreType)));
+            } else {
+                _data = InvalidAddress;
+            }
+        };
+
+        void allocate_and_copy(const void* data, size_t size) {
+            allocate(size);
+            copy(data, size);
+        }
+
+        void allocate_plus_1_and_copy(const void* data, size_t size) {
+            allocate(size+1);
+            copy(data, size);
+        }
+
+        void access_hook(void) const {
+            if ( UseMSAN == true ) {
+                memory::memory_test_msan(_data, _size);
+            }
+        }
+
+        void free(void) {
+            access_hook();
+
+            if ( _data != InvalidAddress ) {
+                std::free(_data);
+                _data = InvalidAddress;
+                _size = 0;
+            }
+        }
+
+#endif
+
+    public:
+#ifndef FUZZING_HEADERS_NO_IMPL
+        CoreType* data(void) {
+            access_hook();
+            return _data;
+        }
+
+        size_t size(void) const {
+            access_hook();
+            return _size;
+        }
+#endif
+
+        Container(void)
+#ifndef FUZZING_HEADERS_NO_IMPL
+        = default
+#endif
+        ;
+
+        Container(const void* data, const size_t size)
+#ifndef FUZZING_HEADERS_NO_IMPL
+        {
+            if ( NullTerminated == false ) {
+                allocate_and_copy(data, size);
+            } else {
+                allocate_plus_1_and_copy(data, size);
+                _data[size] = 0;
+            }
+
+            access_hook();
+        }
+#endif
+        ;
+
+        template<class T>
+        Container(const T& t)
+#ifndef FUZZING_HEADERS_NO_IMPL
+        {
+            Container(t.data(), t.size());
+        }
+#endif
+        ;
+
+        ~Container(void)
+#ifndef FUZZING_HEADERS_NO_IMPL
+        {
+            this->free();
+        }
+#endif
+        ;
+
+
+
+        // The copy constructor was not originally explicitly supplied
+        // so it must have been incorrectly just copying the pointers.
+        Container(const Container &c) {
+          InvalidAddress = c.InvalidAddress;
+          allocate_and_copy(c._data, c._size);
+        }
+
+        Container& operator=(Container &c) {
+          InvalidAddress = c.InvalidAddress;
+          allocate_and_copy(c._data, c._size);
+        }
+
+};
+
+template <bool UseMSAN = false> using String = Container<char, true, UseMSAN>;
+template <bool UseMSAN = false> using Data = Container<uint8_t, false, UseMSAN>;
+
+} /* namespace types */
+} /* namespace fuzzing */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..bde3647
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,41 @@
+cmake_minimum_required(VERSION 3.11)
+
+option(ENABLE_64_BIT_WORDS "Set FLAC__BYTES_PER_WORD to 8 (4 is the default)" OFF)
+option(WITH_XMMS "Build XMMS plugin" OFF)
+option(BUILD_UTILS "Build utils" OFF)
+
+add_subdirectory("libFLAC")
+if(BUILD_CXXLIBS)
+    add_subdirectory("libFLAC++")
+endif()
+add_subdirectory("share/replaygain_analysis")
+add_subdirectory("share/replaygain_synthesis")
+add_subdirectory("share/getopt")
+add_subdirectory("share/utf8")
+add_subdirectory("share/grabbag")
+
+if(BUILD_PROGRAMS)
+    add_subdirectory("flac")
+    add_subdirectory("metaflac")
+endif()
+if(BUILD_UTILS)
+    add_subdirectory(utils/flacdiff)
+    if(WIN32)
+        add_subdirectory(utils/flactimer)
+    endif()
+endif()
+
+if(WITH_XMMS)
+    add_subdirectory("plugin_common")
+    add_subdirectory("plugin_xmms")
+endif()
+if(BUILD_TESTING)
+    add_subdirectory("test_libs_common")
+    add_subdirectory("test_libFLAC")
+    if(BUILD_CXXLIBS)
+        add_subdirectory("test_libFLAC++")
+    endif()
+    add_subdirectory("test_grabbag")
+    add_subdirectory("test_seeking")
+    add_subdirectory("test_streams")
+endif()
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..fcc3cfb
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,43 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+if FLaC__HAS_XMMS
+XMMS_DIRS = plugin_common plugin_xmms
+endif
+
+if FLaC__WITH_CPPLIBS
+CPPLIBS_DIRS = libFLAC++ test_libFLAC++
+endif
+
+SUBDIRS = \
+	libFLAC \
+	share \
+	flac \
+	metaflac \
+	$(XMMS_DIRS) \
+	test_grabbag \
+	test_libs_common \
+	test_libFLAC \
+	test_seeking \
+	test_streams \
+	utils \
+	$(CPPLIBS_DIRS)
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite
diff --git a/src/Makefile.lite b/src/Makefile.lite
new file mode 100644
index 0000000..7e297c3
--- /dev/null
+++ b/src/Makefile.lite
@@ -0,0 +1,76 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+topdir = ..
+
+include $(topdir)/build/config.mk
+
+ifeq ($(OS),Darwin)
+    EXTRA_TARGETS =
+else
+ifeq ($(PROC),x86_64)
+    EXTRA_TARGETS =
+else
+	# Can add plugin_xmms here if desired.
+    EXTRA_TARGETS =
+endif
+endif
+
+ifeq ($(findstring Windows,$(OS)),Windows)
+    EXTRA_TARGETS += share/win_utf8_io
+endif
+
+.PHONY: all flac libFLAC libFLAC++ metaflac plugin_common plugin_xmms share/win_utf8_io share test_grabbag test_libs_common test_libFLAC test_libFLAC++ test_seeking test_streams flacdiff flactimer
+all: flac libFLAC libFLAC++ metaflac plugin_common $(EXTRA_TARGETS) share test_grabbag test_libs_common test_libFLAC test_libFLAC++ test_seeking test_streams
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+flac libFLAC libFLAC++ metaflac plugin_common plugin_xmms share/win_utf8_io share test_grabbag test_libs_common test_libFLAC test_libFLAC++ test_seeking test_streams:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+flacdiff flactimer:
+	(cd utils/$@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+clean:
+	-(cd flac ; $(MAKE) -f Makefile.lite clean)
+	-(cd libFLAC ; $(MAKE) -f Makefile.lite clean)
+	-(cd libFLAC++ ; $(MAKE) -f Makefile.lite clean)
+	-(cd metaflac ; $(MAKE) -f Makefile.lite clean)
+	-(cd plugin_common ; $(MAKE) -f Makefile.lite clean)
+	-(cd plugin_xmms ; $(MAKE) -f Makefile.lite clean)
+	-(cd share ; $(MAKE) -f Makefile.lite clean)
+	-(cd test_grabbag ; $(MAKE) -f Makefile.lite clean)
+	-(cd test_libs_common ; $(MAKE) -f Makefile.lite clean)
+	-(cd test_libFLAC ; $(MAKE) -f Makefile.lite clean)
+	-(cd test_libFLAC++ ; $(MAKE) -f Makefile.lite clean)
+	-(cd test_seeking ; $(MAKE) -f Makefile.lite clean)
+	-(cd test_streams ; $(MAKE) -f Makefile.lite clean)
+	-(cd utils/flacdiff ; $(MAKE) -f Makefile.lite clean)
+	-(cd utils/flactimer ; $(MAKE) -f Makefile.lite clean)
+
+include $(topdir)/Makefile.deps
diff --git a/src/flac/CMakeLists.txt b/src/flac/CMakeLists.txt
new file mode 100644
index 0000000..c227cd8
--- /dev/null
+++ b/src/flac/CMakeLists.txt
@@ -0,0 +1,23 @@
+check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H)
+check_include_file("termios.h" HAVE_TERMIOS_H)
+
+add_executable(flacapp
+    analyze.c
+    decode.c
+    encode.c
+    foreign_metadata.c
+    main.c
+    local_string_utils.c
+    utils.c
+    vorbiscomment.c
+    $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+    $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+set_property(TARGET flacapp PROPERTY RUNTIME_OUTPUT_NAME flac)
+target_link_libraries(flacapp
+    FLAC
+    getopt
+    replaygain_synthesis
+    utf8)
+
+install(TARGETS flacapp EXPORT targets
+    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
diff --git a/src/flac/Makefile.am b/src/flac/Makefile.am
new file mode 100644
index 0000000..679e2ee
--- /dev/null
+++ b/src/flac/Makefile.am
@@ -0,0 +1,67 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+bin_PROGRAMS = flac
+
+AM_CFLAGS = @OGG_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	Makefile.lite.iffscan \
+	flac.vcproj \
+	flac.vcxproj \
+	flac.vcxproj.filters \
+	iffscan.c \
+	iffscan.vcproj \
+	iffscan.vcxproj \
+	iffscan.vcxproj.filters
+
+flac_SOURCES = \
+	analyze.c \
+	decode.c \
+	encode.c \
+	foreign_metadata.c \
+	main.c \
+	local_string_utils.c \
+	utils.c \
+	vorbiscomment.c \
+	analyze.h \
+	decode.h \
+	encode.h \
+	foreign_metadata.h \
+	local_string_utils.h \
+	utils.h \
+	vorbiscomment.h
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+flac_LDADD = \
+	$(top_builddir)/src/share/utf8/libutf8.la \
+	$(top_builddir)/src/share/grabbag/libgrabbag.la \
+	$(top_builddir)/src/share/getopt/libgetopt.la \
+	$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+	$(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
+	$(top_builddir)/src/libFLAC/libFLAC.la \
+	$(win_utf8_lib) \
+	@LTLIBICONV@ \
+	-lm
+
+CLEANFILES = flac.exe
diff --git a/src/flac/Makefile.lite b/src/flac/Makefile.lite
new file mode 100644
index 0000000..d6553cf
--- /dev/null
+++ b/src/flac/Makefile.lite
@@ -0,0 +1,54 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = flac
+
+INCLUDES = -I./include -I$(topdir)/include $(OGG_INCLUDES)
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libFLAC.a $(libdir)/libreplaygain_analysis.a $(libdir)/libreplaygain_synthesis.a $(libdir)/libgetopt.a $(libdir)/libutf8.a $(OGG_EXPLICIT_LIBS) $(ICONV_LIBS) -lm
+else
+ifeq ($(findstring Windows,$(OS)),Windows)
+    LIBS = -lgrabbag -lFLAC -lreplaygain_analysis -lreplaygain_synthesis -lgetopt -lutf8 -lgrabbag -lwin_utf8_io $(OGG_LIBS) -lm
+else
+    LIBS = -lgrabbag -lFLAC -lreplaygain_analysis -lreplaygain_synthesis -lgetopt -lutf8 -lgrabbag $(OGG_LIBS) -lm
+endif
+endif
+
+SRCS_C = \
+	analyze.c \
+	decode.c \
+	encode.c \
+	foreign_metadata.c \
+	local_string_utils.c \
+	main.c \
+	utils.c \
+	vorbiscomment.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/flac/Makefile.lite.iffscan b/src/flac/Makefile.lite.iffscan
new file mode 100644
index 0000000..65c6084
--- /dev/null
+++ b/src/flac/Makefile.lite.iffscan
@@ -0,0 +1,46 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = iffscan
+
+INCLUDES = -I./include -I$(topdir)/include $(OGG_INCLUDES)
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) $(ICONV_LIBS) -lm
+else
+ifeq ($(findstring Windows,$(OS)),Windows)
+    LIBS = -lFLAC -lwin_utf8_io $(OGG_LIBS) -lm
+else
+    LIBS = -lFLAC $(OGG_LIBS) -lm
+endif
+endif
+
+SRCS_C = \
+	foreign_metadata.c \
+	iffscan.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/flac/analyze.c b/src/flac/analyze.c
new file mode 100644
index 0000000..683b644
--- /dev/null
+++ b/src/flac/analyze.c
@@ -0,0 +1,247 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FLAC/all.h"
+#include "analyze.h"
+
+#include "share/compat.h"
+
+typedef struct {
+	FLAC__int32 residual;
+	uint32_t count;
+} pair_t;
+
+typedef struct {
+	pair_t buckets[FLAC__MAX_BLOCK_SIZE];
+	int peak_index;
+	uint32_t nbuckets;
+	uint32_t nsamples;
+	double sum, sos;
+	double variance;
+	double mean;
+	double stddev;
+} subframe_stats_t;
+
+static subframe_stats_t all_;
+
+static void init_stats(subframe_stats_t *stats);
+static void update_stats(subframe_stats_t *stats, FLAC__int32 residual, uint32_t incr);
+static void compute_stats(subframe_stats_t *stats);
+static FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename);
+
+void flac__analyze_init(analysis_options aopts)
+{
+	if(aopts.do_residual_gnuplot) {
+		init_stats(&all_);
+	}
+}
+
+void flac__analyze_frame(const FLAC__Frame *frame, uint32_t frame_number, FLAC__uint64 frame_offset, uint32_t frame_bytes, analysis_options aopts, FILE *fout)
+{
+	const uint32_t channels = frame->header.channels;
+	char outfilename[1024];
+	subframe_stats_t stats;
+	uint32_t i, channel, partitions;
+
+	/* do the human-readable part first */
+	fprintf(fout, "frame=%u\toffset=%" PRIu64 "\tbits=%u\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", frame_number, frame_offset, frame_bytes*8, frame->header.blocksize, frame->header.sample_rate, channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]);
+	for(channel = 0; channel < channels; channel++) {
+		const FLAC__Subframe *subframe = frame->subframes+channel;
+		const FLAC__bool is_rice2 = subframe->data.fixed.entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2;
+		const uint32_t pesc = is_rice2? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+		fprintf(fout, "\tsubframe=%u\twasted_bits=%u\ttype=%s", channel, subframe->wasted_bits, FLAC__SubframeTypeString[subframe->type]);
+		switch(subframe->type) {
+			case FLAC__SUBFRAME_TYPE_CONSTANT:
+				fprintf(fout, "\tvalue=%d\n", subframe->data.constant.value);
+				break;
+			case FLAC__SUBFRAME_TYPE_FIXED:
+				FLAC__ASSERT(subframe->data.fixed.entropy_coding_method.type <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2);
+				fprintf(fout, "\torder=%u\tresidual_type=%s\tpartition_order=%u\n", subframe->data.fixed.order, is_rice2? "RICE2":"RICE", subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order);
+				for(i = 0; i < subframe->data.fixed.order; i++)
+					fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.fixed.warmup[i]);
+				partitions = (1u << subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order);
+				for(i = 0; i < partitions; i++) {
+					uint32_t parameter = subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->parameters[i];
+					if(parameter == pesc)
+						fprintf(fout, "\t\tparameter[%u]=ESCAPE, raw_bits=%u\n", i, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->raw_bits[i]);
+					else
+						fprintf(fout, "\t\tparameter[%u]=%u\n", i, parameter);
+				}
+				if(aopts.do_residual_text) {
+					for(i = 0; i < frame->header.blocksize-subframe->data.fixed.order; i++)
+						fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.fixed.residual[i]);
+				}
+				break;
+			case FLAC__SUBFRAME_TYPE_LPC:
+				FLAC__ASSERT(subframe->data.lpc.entropy_coding_method.type <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2);
+				fprintf(fout, "\torder=%u\tqlp_coeff_precision=%u\tquantization_level=%d\tresidual_type=%s\tpartition_order=%u\n", subframe->data.lpc.order, subframe->data.lpc.qlp_coeff_precision, subframe->data.lpc.quantization_level, is_rice2? "RICE2":"RICE", subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order);
+				for(i = 0; i < subframe->data.lpc.order; i++)
+					fprintf(fout, "\t\tqlp_coeff[%u]=%d\n", i, subframe->data.lpc.qlp_coeff[i]);
+				for(i = 0; i < subframe->data.lpc.order; i++)
+					fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.lpc.warmup[i]);
+				partitions = (1u << subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order);
+				for(i = 0; i < partitions; i++) {
+					uint32_t parameter = subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->parameters[i];
+					if(parameter == pesc)
+						fprintf(fout, "\t\tparameter[%u]=ESCAPE, raw_bits=%u\n", i, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->raw_bits[i]);
+					else
+						fprintf(fout, "\t\tparameter[%u]=%u\n", i, parameter);
+				}
+				if(aopts.do_residual_text) {
+					for(i = 0; i < frame->header.blocksize-subframe->data.lpc.order; i++)
+						fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.lpc.residual[i]);
+				}
+				break;
+			case FLAC__SUBFRAME_TYPE_VERBATIM:
+				fprintf(fout, "\n");
+				break;
+		}
+	}
+
+	/* now do the residual distributions if requested */
+	if(aopts.do_residual_gnuplot) {
+		for(channel = 0; channel < channels; channel++) {
+			const FLAC__Subframe *subframe = frame->subframes+channel;
+			uint32_t residual_samples;
+
+			init_stats(&stats);
+
+			switch(subframe->type) {
+				case FLAC__SUBFRAME_TYPE_FIXED:
+					residual_samples = frame->header.blocksize - subframe->data.fixed.order;
+					for(i = 0; i < residual_samples; i++)
+						update_stats(&stats, subframe->data.fixed.residual[i], 1);
+					break;
+				case FLAC__SUBFRAME_TYPE_LPC:
+					residual_samples = frame->header.blocksize - subframe->data.lpc.order;
+					for(i = 0; i < residual_samples; i++)
+						update_stats(&stats, subframe->data.lpc.residual[i], 1);
+					break;
+				default:
+					break;
+			}
+
+			/* update all_ */
+			for(i = 0; i < stats.nbuckets; i++) {
+				update_stats(&all_, stats.buckets[i].residual, stats.buckets[i].count);
+			}
+
+			/* write the subframe */
+			flac_snprintf(outfilename, sizeof (outfilename), "f%06u.s%u.gp", frame_number, channel);
+			compute_stats(&stats);
+
+			(void)dump_stats(&stats, outfilename);
+		}
+	}
+}
+
+void flac__analyze_finish(analysis_options aopts)
+{
+	if(aopts.do_residual_gnuplot) {
+		compute_stats(&all_);
+		(void)dump_stats(&all_, "all");
+	}
+}
+
+void init_stats(subframe_stats_t *stats)
+{
+	stats->peak_index = -1;
+	stats->nbuckets = 0;
+	stats->nsamples = 0;
+	stats->sum = 0.0;
+	stats->sos = 0.0;
+}
+
+void update_stats(subframe_stats_t *stats, FLAC__int32 residual, uint32_t incr)
+{
+	uint32_t i;
+	const double r = (double)residual, a = r*incr;
+
+	stats->nsamples += incr;
+	stats->sum += a;
+	stats->sos += (a*r);
+
+	for(i = 0; i < stats->nbuckets; i++) {
+		if(stats->buckets[i].residual == residual) {
+			stats->buckets[i].count += incr;
+			goto find_peak;
+		}
+	}
+	/* not found, make a new bucket */
+	i = stats->nbuckets;
+	stats->buckets[i].residual = residual;
+	stats->buckets[i].count = incr;
+	stats->nbuckets++;
+find_peak:
+	if(stats->peak_index < 0 || stats->buckets[i].count > stats->buckets[stats->peak_index].count)
+		stats->peak_index = i;
+}
+
+void compute_stats(subframe_stats_t *stats)
+{
+	stats->mean = stats->sum / (double)stats->nsamples;
+	stats->variance = (stats->sos - (stats->sum * stats->sum / stats->nsamples)) / stats->nsamples;
+	stats->stddev = sqrt(stats->variance);
+}
+
+FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename)
+{
+	FILE *outfile;
+	uint32_t i;
+	const double m = stats->mean;
+	const double s1 = stats->stddev, s2 = s1*2, s3 = s1*3, s4 = s1*4, s5 = s1*5, s6 = s1*6;
+	const double p = stats->buckets[stats->peak_index].count;
+
+	outfile = flac_fopen(filename, "w");
+
+	if(0 == outfile) {
+		fprintf(stderr, "ERROR opening %s: %s\n", filename, strerror(errno));
+		return false;
+	}
+
+	fprintf(outfile, "plot '-' title 'PDF', '-' title 'mean' with impulses, '-' title '1-stddev' with histeps, '-' title '2-stddev' with histeps, '-' title '3-stddev' with histeps, '-' title '4-stddev' with histeps, '-' title '5-stddev' with histeps, '-' title '6-stddev' with histeps\n");
+
+	for(i = 0; i < stats->nbuckets; i++) {
+		fprintf(outfile, "%d %u\n", stats->buckets[i].residual, stats->buckets[i].count);
+	}
+	fprintf(outfile, "e\n");
+
+	fprintf(outfile, "%f %f\ne\n", stats->mean, p);
+	fprintf(outfile, "%f %f\n%f %f\ne\n", m-s1, p*0.8, m+s1, p*0.8);
+	fprintf(outfile, "%f %f\n%f %f\ne\n", m-s2, p*0.7, m+s2, p*0.7);
+	fprintf(outfile, "%f %f\n%f %f\ne\n", m-s3, p*0.6, m+s3, p*0.6);
+	fprintf(outfile, "%f %f\n%f %f\ne\n", m-s4, p*0.5, m+s4, p*0.5);
+	fprintf(outfile, "%f %f\n%f %f\ne\n", m-s5, p*0.4, m+s5, p*0.4);
+	fprintf(outfile, "%f %f\n%f %f\ne\n", m-s6, p*0.3, m+s6, p*0.3);
+
+	fprintf(outfile, "pause -1 'waiting...'\n");
+
+	fclose(outfile);
+	return true;
+}
diff --git a/src/flac/analyze.h b/src/flac/analyze.h
new file mode 100644
index 0000000..44798c7
--- /dev/null
+++ b/src/flac/analyze.h
@@ -0,0 +1,32 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__analyze_h
+#define flac__analyze_h
+
+typedef struct {
+	FLAC__bool do_residual_text;
+	FLAC__bool do_residual_gnuplot;
+} analysis_options;
+
+void flac__analyze_init(analysis_options aopts);
+void flac__analyze_frame(const FLAC__Frame *frame, uint32_t frame_number, FLAC__uint64 frame_offset, uint32_t frame_bytes, analysis_options aopts, FILE *fout);
+void flac__analyze_finish(analysis_options aopts);
+
+#endif
diff --git a/src/flac/decode.c b/src/flac/decode.c
new file mode 100644
index 0000000..c26d3f6
--- /dev/null
+++ b/src/flac/decode.c
@@ -0,0 +1,1501 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <math.h> /* for floor() */
+#include <stdio.h> /* for FILE etc. */
+#include <string.h> /* for strcmp(), strerror() */
+#include "FLAC/all.h"
+#include "share/grabbag.h"
+#include "share/replaygain_synthesis.h"
+#include "share/compat.h"
+#include "decode.h"
+
+typedef struct {
+#if FLAC__HAS_OGG
+	FLAC__bool is_ogg;
+	FLAC__bool use_first_serial_number;
+	long serial_number;
+#endif
+
+	FileFormat format;
+	FLAC__bool treat_warnings_as_errors;
+	FLAC__bool continue_through_decode_errors;
+	FLAC__bool channel_map_none;
+
+	struct {
+		replaygain_synthesis_spec_t spec;
+		FLAC__bool apply; /* 'spec.apply' is just a request; this 'apply' means we actually parsed the RG tags and are ready to go */
+		double scale;
+		DitherContext dither_context;
+	} replaygain;
+
+	FLAC__bool test_only;
+	FLAC__bool analysis_mode;
+	analysis_options aopts;
+	utils__SkipUntilSpecification *skip_specification;
+	utils__SkipUntilSpecification *until_specification; /* a canonicalized value of 0 mean end-of-stream (i.e. --until=-0) */
+	utils__CueSpecification *cue_specification;
+
+	const char *inbasefilename;
+	const char *infilename;
+	const char *outfilename;
+
+	FLAC__uint64 samples_processed;
+	uint32_t frame_counter;
+	FLAC__bool abort_flag;
+	FLAC__bool aborting_due_to_until; /* true if we intentionally abort decoding prematurely because we hit the --until point */
+	FLAC__bool aborting_due_to_unparseable; /* true if we abort decoding because we hit an unparseable frame */
+	FLAC__bool error_callback_suppress_messages; /* turn on to prevent repeating messages from the error callback */
+
+	FLAC__bool iff_headers_need_fixup;
+
+	FLAC__bool is_big_endian;
+	FLAC__bool is_unsigned_samples;
+	FLAC__bool got_stream_info;
+	FLAC__bool has_md5sum;
+	FLAC__uint64 total_samples;
+	uint32_t bps;
+	uint32_t channels;
+	uint32_t sample_rate;
+	FLAC__uint32 channel_mask;
+
+	/* these are used only in analyze mode */
+	FLAC__uint64 decode_position;
+
+	FLAC__StreamDecoder *decoder;
+
+	FILE *fout;
+
+	foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */
+	FLAC__off_t fm_offset1, fm_offset2, fm_offset3;
+} DecoderSession;
+
+
+static FLAC__bool is_big_endian_host_;
+
+
+/*
+ * local routines
+ */
+static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FileFormat format, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename);
+static void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred);
+static FLAC__bool DecoderSession_init_decoder(DecoderSession *d, const char *infilename);
+static FLAC__bool DecoderSession_process(DecoderSession *d);
+static int DecoderSession_finish_ok(DecoderSession *d);
+static int DecoderSession_finish_error(DecoderSession *d);
+static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input);
+static FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples);
+static FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatextensible, uint32_t bps, uint32_t channels, uint32_t sample_rate, FLAC__uint32 channel_mask);
+static FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate);
+static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val);
+static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val);
+static FLAC__bool write_little_endian_uint64(FILE *f, FLAC__uint64 val);
+static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 val);
+static FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 val);
+static FLAC__bool write_sane_extended(FILE *f, uint32_t val);
+static FLAC__bool fixup_iff_headers(DecoderSession *d);
+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 void print_error_with_init_status(const DecoderSession *d, const char *message, FLAC__StreamDecoderInitStatus init_status);
+static void print_error_with_state(const DecoderSession *d, const char *message);
+static void print_stats(const DecoderSession *decoder_session);
+
+
+/*
+ * public routines
+ */
+int flac__decode_file(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, decode_options_t options)
+{
+	DecoderSession decoder_session;
+
+	FLAC__ASSERT(
+		options.format == FORMAT_WAVE ||
+		options.format == FORMAT_WAVE64 ||
+		options.format == FORMAT_RF64 ||
+		options.format == FORMAT_AIFF ||
+		options.format == FORMAT_AIFF_C ||
+		options.format == FORMAT_RAW
+	);
+
+	if(options.format == FORMAT_RAW) {
+		decoder_session.is_big_endian = options.format_options.raw.is_big_endian;
+		decoder_session.is_unsigned_samples = options.format_options.raw.is_unsigned_samples;
+	}
+
+	if(!
+		DecoderSession_construct(
+			&decoder_session,
+#if FLAC__HAS_OGG
+			options.is_ogg,
+			options.use_first_serial_number,
+			options.serial_number,
+#else
+			/*is_ogg=*/false,
+			/*use_first_serial_number=*/false,
+			/*serial_number=*/0,
+#endif
+			options.format,
+			options.treat_warnings_as_errors,
+			options.continue_through_decode_errors,
+			options.channel_map_none,
+			options.replaygain_synthesis_spec,
+			analysis_mode,
+			aopts,
+			&options.skip_specification,
+			&options.until_specification,
+			options.has_cue_specification? &options.cue_specification : 0,
+			options.format == FORMAT_RAW? NULL : options.format_options.iff.foreign_metadata,
+			infilename,
+			outfilename
+		)
+	)
+		return 1;
+
+	stats_new_file();
+	if(!DecoderSession_init_decoder(&decoder_session, infilename))
+		return DecoderSession_finish_error(&decoder_session);
+
+	if(!DecoderSession_process(&decoder_session))
+		return DecoderSession_finish_error(&decoder_session);
+
+	return DecoderSession_finish_ok(&decoder_session);
+}
+
+FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FileFormat format, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename)
+{
+#if FLAC__HAS_OGG
+	d->is_ogg = is_ogg;
+	d->use_first_serial_number = use_first_serial_number;
+	d->serial_number = serial_number;
+#else
+	(void)is_ogg;
+	(void)use_first_serial_number;
+	(void)serial_number;
+#endif
+
+	d->format = format;
+	d->treat_warnings_as_errors = treat_warnings_as_errors;
+	d->continue_through_decode_errors = continue_through_decode_errors;
+	d->channel_map_none = channel_map_none;
+	d->replaygain.spec = replaygain_synthesis_spec;
+	d->replaygain.apply = false;
+	d->replaygain.scale = 0.0;
+	/* d->replaygain.dither_context gets initialized later once we know the sample resolution */
+	d->test_only = (0 == outfilename);
+	d->analysis_mode = analysis_mode;
+	d->aopts = aopts;
+	d->skip_specification = skip_specification;
+	d->until_specification = until_specification;
+	d->cue_specification = cue_specification;
+
+	d->inbasefilename = grabbag__file_get_basename(infilename);
+	d->infilename = infilename;
+	d->outfilename = outfilename;
+
+	d->samples_processed = 0;
+	d->frame_counter = 0;
+	d->abort_flag = false;
+	d->aborting_due_to_until = false;
+	d->aborting_due_to_unparseable = false;
+	d->error_callback_suppress_messages = false;
+
+	d->iff_headers_need_fixup = false;
+
+	d->total_samples = 0;
+	d->got_stream_info = false;
+	d->has_md5sum = false;
+	d->bps = 0;
+	d->channels = 0;
+	d->sample_rate = 0;
+	d->channel_mask = 0;
+
+	d->decode_position = 0;
+
+	d->decoder = 0;
+
+	d->fout = 0; /* initialized with an open file later if necessary */
+
+	d->foreign_metadata = foreign_metadata;
+
+	FLAC__ASSERT(!(d->test_only && d->analysis_mode));
+
+	if(!d->test_only) {
+		if(0 == strcmp(outfilename, "-")) {
+			d->fout = grabbag__file_get_binary_stdout();
+		}
+		else {
+			if(0 == (d->fout = flac_fopen(outfilename, "wb"))) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: can't open output file %s: %s\n", d->inbasefilename, outfilename, strerror(errno));
+				DecoderSession_destroy(d, /*error_occurred=*/true);
+				return false;
+			}
+		}
+	}
+
+	if(analysis_mode)
+		flac__analyze_init(aopts);
+
+	return true;
+}
+
+void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred)
+{
+	if(0 != d->fout && d->fout != stdout) {
+#if defined _WIN32 && !defined __CYGWIN__
+		if(!error_occurred) {
+			FLAC__off_t written_size = ftello(d->fout);
+			if(written_size > 0) {
+				HANDLE fh = CreateFile_utf8(d->outfilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+				if(fh != INVALID_HANDLE_VALUE) {
+					if(GetFileType(fh) == FILE_TYPE_DISK) {
+						LARGE_INTEGER size;
+						size.QuadPart = written_size;
+						if(SetFilePointerEx(fh, size, NULL, FILE_CURRENT)) /* correct the file size */
+							SetEndOfFile(fh);
+					}
+					CloseHandle(fh);
+				}
+			}
+		}
+#endif
+		fclose(d->fout);
+		if(error_occurred)
+			flac_unlink(d->outfilename);
+	}
+}
+
+FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const char *infilename)
+{
+	FLAC__StreamDecoderInitStatus init_status;
+	FLAC__uint32 test = 1;
+
+	is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
+
+	if(!decoder_session->analysis_mode && !decoder_session->test_only && decoder_session->foreign_metadata) {
+		const char *error;
+		if(!flac__foreign_metadata_read_from_flac(decoder_session->foreign_metadata, infilename, &error)) {
+			flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", decoder_session->inbasefilename, error);
+			return false;
+		}
+	}
+
+	decoder_session->decoder = FLAC__stream_decoder_new();
+
+	if(0 == decoder_session->decoder) {
+		flac__utils_printf(stderr, 1, "%s: ERROR creating the decoder instance\n", decoder_session->inbasefilename);
+		return false;
+	}
+
+	FLAC__stream_decoder_set_md5_checking(decoder_session->decoder, true);
+	if (0 != decoder_session->cue_specification)
+		FLAC__stream_decoder_set_metadata_respond(decoder_session->decoder, FLAC__METADATA_TYPE_CUESHEET);
+	if (decoder_session->replaygain.spec.apply || !decoder_session->channel_map_none)
+		FLAC__stream_decoder_set_metadata_respond(decoder_session->decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+#if FLAC__HAS_OGG
+	if(decoder_session->is_ogg) {
+		if(!decoder_session->use_first_serial_number)
+			FLAC__stream_decoder_set_ogg_serial_number(decoder_session->decoder, decoder_session->serial_number);
+		init_status = FLAC__stream_decoder_init_ogg_file(decoder_session->decoder, strcmp(infilename, "-")? infilename : 0, write_callback, metadata_callback, error_callback, /*client_data=*/decoder_session);
+	}
+	else
+#endif
+	{
+		init_status = FLAC__stream_decoder_init_file(decoder_session->decoder, strcmp(infilename, "-")? infilename : 0, write_callback, metadata_callback, error_callback, /*client_data=*/decoder_session);
+	}
+
+	if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		print_error_with_init_status(decoder_session, "ERROR initializing decoder", init_status);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool DecoderSession_process(DecoderSession *d)
+{
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(d->decoder)) {
+		flac__utils_printf(stderr, 2, "\n");
+		print_error_with_state(d, "ERROR while decoding metadata");
+		return false;
+	}
+	if(FLAC__stream_decoder_get_state(d->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM) {
+		flac__utils_printf(stderr, 2, "\n");
+		print_error_with_state(d, "ERROR during metadata decoding");
+		if(!d->continue_through_decode_errors)
+			return false;
+	}
+
+	if(d->abort_flag)
+		return false;
+
+	/* set channel mapping */
+	/* currently FLAC order matches SMPTE/WAVEFORMATEXTENSIBLE order, so no reordering is necessary; see encode.c */
+	/* only the channel mask must be set if it was not already picked up from the WAVEFORMATEXTENSIBLE_CHANNEL_MASK tag */
+	if(!d->channel_map_none && d->channel_mask == 0) {
+		if(d->channels == 1) {
+			d->channel_mask = 0x0004;
+		}
+		else if(d->channels == 2) {
+			d->channel_mask = 0x0003;
+		}
+		else if(d->channels == 3) {
+			d->channel_mask = 0x0007;
+		}
+		else if(d->channels == 4) {
+			d->channel_mask = 0x0033;
+		}
+		else if(d->channels == 5) {
+			d->channel_mask = 0x0607;
+		}
+		else if(d->channels == 6) {
+			d->channel_mask = 0x060f;
+		}
+		else if(d->channels == 7) {
+			d->channel_mask = 0x070f;
+		}
+		else if(d->channels == 8) {
+			d->channel_mask = 0x063f;
+		}
+	}
+
+#if defined _WIN32 && !defined __CYGWIN__
+	if(!d->analysis_mode && !d->test_only && d->total_samples > 0 && d->fout != stdout) {
+		HANDLE fh = CreateFile_utf8(d->outfilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+		if(fh != INVALID_HANDLE_VALUE) {
+			if (GetFileType(fh) == FILE_TYPE_DISK) {
+				LARGE_INTEGER size;
+				size.QuadPart = d->total_samples * d->channels * ((d->bps+7)/8);
+				if(d->format != FORMAT_RAW) {
+					size.QuadPart += 512;
+					if(d->foreign_metadata) {
+						size_t i;
+						for(i = d->format==FORMAT_RF64?2:1; i < d->foreign_metadata->num_blocks; i++) {
+							if(i != d->foreign_metadata->format_block && i != d->foreign_metadata->audio_block)
+								size.QuadPart += d->foreign_metadata->blocks[i].size;
+						}
+					}
+				}
+
+				if(SetFilePointerEx(fh, size, NULL, FILE_CURRENT)) /* tell filesystem the expected filesize to eliminate fragmentation */
+					SetEndOfFile(fh);
+			}
+			CloseHandle(fh);
+		}
+	}
+#endif
+
+	/* write the WAVE/AIFF headers if necessary */
+	if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) {
+		if(!write_iff_headers(d->fout, d, d->total_samples)) {
+			d->abort_flag = true;
+			return false;
+		}
+	}
+
+	if(d->skip_specification->value.samples > 0) {
+		const FLAC__uint64 skip = (FLAC__uint64)d->skip_specification->value.samples;
+
+		if(!FLAC__stream_decoder_seek_absolute(d->decoder, skip)) {
+			print_error_with_state(d, "ERROR seeking while skipping bytes");
+			return false;
+		}
+	}
+	if(!FLAC__stream_decoder_process_until_end_of_stream(d->decoder) && !d->aborting_due_to_until) {
+		flac__utils_printf(stderr, 2, "\n");
+		print_error_with_state(d, "ERROR while decoding data");
+		if(!d->continue_through_decode_errors)
+			return false;
+	}
+	if(
+		(d->abort_flag && !(d->aborting_due_to_until || d->continue_through_decode_errors)) ||
+		(FLAC__stream_decoder_get_state(d->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM && !d->aborting_due_to_until)
+	) {
+		flac__utils_printf(stderr, 2, "\n");
+		print_error_with_state(d, "ERROR during decoding");
+		return false;
+	}
+
+	/* write padding bytes for alignment if necessary */
+	if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) {
+		const FLAC__uint64 data_size = d->total_samples * d->channels * ((d->bps+7)/8);
+		uint32_t padding;
+		if(d->format != FORMAT_WAVE64) {
+			padding = (uint32_t)(data_size & 1);
+		}
+		else {
+			/* 8-byte alignment for Wave64 */
+			padding = (8 - (uint32_t)(data_size & 7)) & 7;
+		}
+		for( ; padding > 0; --padding) {
+			if(flac__utils_fwrite("\000", 1, 1, d->fout) != 1) {
+				print_error_with_state(
+					d,
+					d->format == FORMAT_WAVE?   "ERROR writing pad byte to WAVE data chunk" :
+					d->format == FORMAT_WAVE64? "ERROR writing pad bytes to WAVE64 data chunk" :
+					d->format == FORMAT_RF64?   "ERROR writing pad byte to RF64 data chunk" :
+					"ERROR writing pad byte to AIFF SSND chunk"
+				);
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+int DecoderSession_finish_ok(DecoderSession *d)
+{
+	FLAC__bool ok = true, md5_failure = false;
+
+	if(d->decoder) {
+		md5_failure = !FLAC__stream_decoder_finish(d->decoder) && !d->aborting_due_to_until;
+		print_stats(d);
+		FLAC__stream_decoder_delete(d->decoder);
+	}
+	if(d->analysis_mode)
+		flac__analyze_finish(d->aopts);
+	if(md5_failure) {
+		stats_print_name(1, d->inbasefilename);
+		flac__utils_printf(stderr, 1, "ERROR, MD5 signature mismatch\n");
+		ok = d->continue_through_decode_errors;
+	}
+	else {
+		if(!d->got_stream_info) {
+			stats_print_name(1, d->inbasefilename);
+			flac__utils_printf(stderr, 1, "WARNING, cannot check MD5 signature since there was no STREAMINFO\n");
+			ok = !d->treat_warnings_as_errors;
+		}
+		else if(!d->has_md5sum) {
+			stats_print_name(1, d->inbasefilename);
+			flac__utils_printf(stderr, 1, "WARNING, cannot check MD5 signature since it was unset in the STREAMINFO\n");
+			ok = !d->treat_warnings_as_errors;
+		}
+		stats_print_name(2, d->inbasefilename);
+		flac__utils_printf(stderr, 2, "%s         \n", d->test_only? "ok           ":d->analysis_mode?"done           ":"done");
+	}
+	DecoderSession_destroy(d, /*error_occurred=*/!ok);
+	if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) {
+		if(d->iff_headers_need_fixup || (!d->got_stream_info && strcmp(d->outfilename, "-"))) {
+			if(!fixup_iff_headers(d))
+				return 1;
+		}
+		if(d->foreign_metadata) {
+			const char *error;
+			if(!flac__foreign_metadata_write_to_iff(d->foreign_metadata, d->infilename, d->outfilename, d->fm_offset1, d->fm_offset2, d->fm_offset3, &error)) {
+				flac__utils_printf(stderr, 1, "ERROR updating foreign metadata from %s to %s: %s\n", d->infilename, d->outfilename, error);
+				return 1;
+			}
+		}
+	}
+	return ok? 0 : 1;
+}
+
+int DecoderSession_finish_error(DecoderSession *d)
+{
+	if(d->decoder) {
+		(void)FLAC__stream_decoder_finish(d->decoder);
+		FLAC__stream_decoder_delete(d->decoder);
+	}
+	if(d->analysis_mode)
+		flac__analyze_finish(d->aopts);
+	DecoderSession_destroy(d, /*error_occurred=*/true);
+	return 1;
+}
+
+FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input)
+{
+	/* convert from mm:ss.sss to sample number if necessary */
+	flac__utils_canonicalize_skip_until_specification(spec, sample_rate);
+
+	/* special case: if "--until=-0", use the special value '0' to mean "end-of-stream" */
+	if(spec->is_relative && spec->value.samples == 0) {
+		spec->is_relative = false;
+		return true;
+	}
+
+	/* in any other case the total samples in the input must be known */
+	if(total_samples_in_input == 0) {
+		flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until when FLAC metadata has total sample count of 0\n", inbasefilename);
+		return false;
+	}
+
+	FLAC__ASSERT(spec->value_is_samples);
+
+	/* convert relative specifications to absolute */
+	if(spec->is_relative) {
+		if(spec->value.samples <= 0)
+			spec->value.samples += (FLAC__int64)total_samples_in_input;
+		else
+			spec->value.samples += skip;
+		spec->is_relative = false;
+	}
+
+	/* error check */
+	if(spec->value.samples < 0) {
+		flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before beginning of input\n", inbasefilename);
+		return false;
+	}
+	if((FLAC__uint64)spec->value.samples <= skip) {
+		flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before --skip point\n", inbasefilename);
+		return false;
+	}
+	if((FLAC__uint64)spec->value.samples > total_samples_in_input) {
+		flac__utils_printf(stderr, 1, "%s: ERROR, --until value is after end of input\n", inbasefilename);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples)
+{
+	const FileFormat format = decoder_session->format;
+	const char *fmt_desc =
+		format==FORMAT_WAVE? "WAVE" :
+		format==FORMAT_WAVE64? "Wave64" :
+		format==FORMAT_RF64? "RF64" :
+		"AIFF";
+	const FLAC__bool is_waveformatextensible =
+		(format == FORMAT_WAVE || format == FORMAT_WAVE64 || format == FORMAT_RF64) &&
+		(
+			(decoder_session->channel_mask != 0 && decoder_session->channel_mask != 0x0004 && decoder_session->channel_mask != 0x0003) ||
+			(decoder_session->bps != 8 && decoder_session->bps != 16) ||
+			decoder_session->channels > 2
+		);
+	const FLAC__uint64 data_size = samples * decoder_session->channels * ((decoder_session->bps+7)/8);
+	const FLAC__uint64 aligned_data_size =
+		format == FORMAT_WAVE64?
+			(data_size+7) & (~(FLAC__uint64)7) :
+			(data_size+1) & (~(FLAC__uint64)1);
+
+	FLAC__uint64 iff_size;
+	uint32_t foreign_metadata_size = 0; /* size of all non-audio non-fmt/COMM foreign metadata chunks */
+	foreign_metadata_t *fm = decoder_session->foreign_metadata;
+	size_t i;
+
+	FLAC__ASSERT(
+		format == FORMAT_WAVE ||
+		format == FORMAT_WAVE64 ||
+		format == FORMAT_RF64 ||
+		format == FORMAT_AIFF ||
+		format == FORMAT_AIFF_C
+	);
+
+	if(samples == 0) {
+		if(f == stdout) {
+			flac__utils_printf(stderr, 1, "%s: WARNING, don't have accurate sample count available for %s header.\n", decoder_session->inbasefilename, fmt_desc);
+			flac__utils_printf(stderr, 1, "             Generated %s file will have a data chunk size of 0.  Try\n", fmt_desc);
+			flac__utils_printf(stderr, 1, "             decoding directly to a file instead.\n");
+			if(decoder_session->treat_warnings_as_errors)
+				return false;
+		}
+		else {
+			decoder_session->iff_headers_need_fixup = true;
+		}
+	}
+
+	if(fm) {
+		FLAC__ASSERT(fm->format_block);
+		FLAC__ASSERT(fm->audio_block);
+		FLAC__ASSERT(fm->format_block < fm->audio_block);
+		/* calc foreign metadata size; we always skip the first chunk, ds64 chunk, format chunk, and sound chunk since we write our own */
+		for(i = format==FORMAT_RF64?2:1; i < fm->num_blocks; i++) {
+			if(i != fm->format_block && i != fm->audio_block)
+				foreign_metadata_size += fm->blocks[i].size;
+		}
+	}
+
+	if(samples == 0)
+		iff_size = 0;
+	else if(format == FORMAT_WAVE || format == FORMAT_RF64)
+		/* 4 for WAVE form bytes */
+		/* +{36,0} for ds64 chunk */
+		/* +8+{40,16} for fmt chunk header and body */
+		/* +8 for data chunk header */
+		iff_size = 4 + (format==FORMAT_RF64?36:0) + 8+(is_waveformatextensible?40:16) + 8 + foreign_metadata_size + aligned_data_size;
+	else if(format == FORMAT_WAVE64)
+		/* 16+8 for RIFF GUID and size field */
+		/* +16 for WAVE GUID */
+		/* +16+8+{40,16} for fmt chunk header (GUID and size field) and body */
+		/* +16+8 for data chunk header (GUID and size field) */
+		iff_size = 16+8 + 16 + 16+8+(is_waveformatextensible?40:16) + 16+8 + foreign_metadata_size + aligned_data_size;
+	else /* AIFF */
+		iff_size = 46 + foreign_metadata_size + aligned_data_size;
+
+	if(format != FORMAT_WAVE64 && format != FORMAT_RF64 && iff_size >= 0xFFFFFFF4) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: stream is too big to fit in a single %s file\n", decoder_session->inbasefilename, fmt_desc);
+		return false;
+	}
+
+	if(format == FORMAT_WAVE || format == FORMAT_WAVE64 || format == FORMAT_RF64) {
+		/* RIFF header */
+		switch(format) {
+			case FORMAT_WAVE:
+				if(flac__utils_fwrite("RIFF", 1, 4, f) != 4)
+					return false;
+				if(!write_little_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */
+					return false;
+				if(flac__utils_fwrite("WAVE", 1, 4, f) != 4)
+					return false;
+				break;
+			case FORMAT_WAVE64:
+				/* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
+				if(flac__utils_fwrite("\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 1, 16, f) != 16)
+					return false;
+				if(!write_little_endian_uint64(f, iff_size))
+					return false;
+				/* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
+				if(flac__utils_fwrite("\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+					return false;
+				break;
+			case FORMAT_RF64:
+				if(flac__utils_fwrite("RF64", 1, 4, f) != 4)
+					return false;
+				if(!write_little_endian_uint32(f, 0xffffffff))
+					return false;
+				if(flac__utils_fwrite("WAVE", 1, 4, f) != 4)
+					return false;
+				break;
+			default:
+				return false;
+		}
+
+		/* ds64 chunk for RF64 */
+		if(format == FORMAT_RF64) {
+			if(flac__utils_fwrite("ds64", 1, 4, f) != 4)
+				return false;
+
+			if(!write_little_endian_uint32(f, 28)) /* chunk size */
+				return false;
+
+			if(!write_little_endian_uint64(f, iff_size))
+				return false;
+
+			if(!write_little_endian_uint64(f, data_size))
+				return false;
+
+			if(!write_little_endian_uint64(f, samples)) /*@@@@@@ correct? */
+				return false;
+
+			if(!write_little_endian_uint32(f, 0)) /* table size */
+				return false;
+		}
+
+		decoder_session->fm_offset1 = ftello(f);
+
+		if(fm) {
+			/* seek forward to {allocate} or {skip over already-written chunks} before "fmt " */
+			for(i = format==FORMAT_RF64?2:1; i < fm->format_block; i++) {
+				if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata before \"fmt \"\n", decoder_session->inbasefilename);
+					return false;
+				}
+			}
+		}
+
+		if(format != FORMAT_WAVE64) {
+			if(flac__utils_fwrite("fmt ", 1, 4, f) != 4)
+				return false;
+			if(!write_little_endian_uint32(f, is_waveformatextensible? 40 : 16)) /* chunk size */
+				return false;
+		}
+		else { /* Wave64 */
+			/* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
+			if(flac__utils_fwrite("\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+				return false;
+			/* chunk size (+16+8 for GUID and size fields) */
+			if(!write_little_endian_uint64(f, 16+8+(is_waveformatextensible?40:16)))
+				return false;
+		}
+
+		if(!write_riff_wave_fmt_chunk_body(f, is_waveformatextensible, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, decoder_session->channel_mask))
+			return false;
+
+		decoder_session->fm_offset2 = ftello(f);
+
+		if(fm) {
+			/* seek forward to {allocate} or {skip over already-written chunks} after "fmt " but before "data" */
+			for(i = fm->format_block+1; i < fm->audio_block; i++) {
+				if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata after \"fmt \"\n", decoder_session->inbasefilename);
+					return false;
+				}
+			}
+		}
+
+		if(format != FORMAT_WAVE64) {
+			if(flac__utils_fwrite("data", 1, 4, f) != 4)
+				return false;
+			if(!write_little_endian_uint32(f, format==FORMAT_RF64? 0xffffffff : (FLAC__uint32)data_size))
+				return false;
+		}
+		else { /* Wave64 */
+			/* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
+			if(flac__utils_fwrite("\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+				return false;
+			/* +16+8 for GUID and size fields */
+			if(!write_little_endian_uint64(f, 16+8 + data_size))
+				return false;
+		}
+
+		decoder_session->fm_offset3 = ftello(f) + aligned_data_size;
+	}
+	else {
+		if(flac__utils_fwrite("FORM", 1, 4, f) != 4)
+			return false;
+
+		if(!write_big_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */
+			return false;
+
+		if(flac__utils_fwrite("AIFF", 1, 4, f) != 4)
+			return false;
+
+		decoder_session->fm_offset1 = ftello(f);
+
+		if(fm) {
+			/* seek forward to {allocate} or {skip over already-written chunks} before "COMM" */
+			for(i = 1; i < fm->format_block; i++) {
+				if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata before \"COMM\"\n", decoder_session->inbasefilename);
+					return false;
+				}
+			}
+		}
+
+		if(!write_aiff_form_comm_chunk(f, samples, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate))
+			return false;
+
+		decoder_session->fm_offset2 = ftello(f);
+
+		if(fm) {
+			/* seek forward to {allocate} or {skip over already-written chunks} after "COMM" but before "SSND" */
+			for(i = fm->format_block+1; i < fm->audio_block; i++) {
+				if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata after \"COMM\"\n", decoder_session->inbasefilename);
+					return false;
+				}
+			}
+		}
+
+		if(flac__utils_fwrite("SSND", 1, 4, f) != 4)
+			return false;
+
+		if(!write_big_endian_uint32(f, (FLAC__uint32)data_size + 8)) /* data size */
+			return false;
+
+		if(!write_big_endian_uint32(f, 0/*offset_size*/))
+			return false;
+
+		if(!write_big_endian_uint32(f, 0/*block_size*/))
+			return false;
+
+		decoder_session->fm_offset3 = ftello(f) + aligned_data_size;
+	}
+
+	return true;
+}
+
+FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatextensible, uint32_t bps, uint32_t channels, uint32_t sample_rate, FLAC__uint32 channel_mask)
+{
+	if(!write_little_endian_uint16(f, (FLAC__uint16)(is_waveformatextensible? 65534 : 1))) /* compression code */
+		return false;
+
+	if(!write_little_endian_uint16(f, (FLAC__uint16)channels))
+		return false;
+
+	if(!write_little_endian_uint32(f, sample_rate))
+		return false;
+
+	if(!write_little_endian_uint32(f, sample_rate * channels * ((bps+7) / 8)))
+		return false;
+
+	if(!write_little_endian_uint16(f, (FLAC__uint16)(channels * ((bps+7) / 8)))) /* block align */
+		return false;
+
+	if(!write_little_endian_uint16(f, (FLAC__uint16)(((bps+7)/8)*8))) /* bits per sample */
+		return false;
+
+	if(is_waveformatextensible) {
+		if(!write_little_endian_uint16(f, (FLAC__uint16)22)) /* cbSize */
+			return false;
+
+		if(!write_little_endian_uint16(f, (FLAC__uint16)bps)) /* validBitsPerSample */
+			return false;
+
+		if(!write_little_endian_uint32(f, channel_mask))
+			return false;
+
+		/* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */
+		if(flac__utils_fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16)
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate)
+{
+	FLAC__ASSERT(samples <= 0xffffffff);
+
+	if(flac__utils_fwrite("COMM", 1, 4, f) != 4)
+		return false;
+
+	if(!write_big_endian_uint32(f, 18)) /* chunk size = 18 */
+		return false;
+
+	if(!write_big_endian_uint16(f, (FLAC__uint16)channels))
+		return false;
+
+	if(!write_big_endian_uint32(f, (FLAC__uint32)samples))
+		return false;
+
+	if(!write_big_endian_uint16(f, (FLAC__uint16)bps))
+		return false;
+
+	if(!write_sane_extended(f, sample_rate))
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val)
+{
+	FLAC__byte *b = (FLAC__byte*)(&val);
+	if(is_big_endian_host_) {
+		FLAC__byte tmp;
+		tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+	}
+	return flac__utils_fwrite(b, 1, 2, f) == 2;
+}
+
+FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val)
+{
+	FLAC__byte *b = (FLAC__byte*)(&val);
+	if(is_big_endian_host_) {
+		FLAC__byte tmp;
+		tmp = b[3]; b[3] = b[0]; b[0] = tmp;
+		tmp = b[2]; b[2] = b[1]; b[1] = tmp;
+	}
+	return flac__utils_fwrite(b, 1, 4, f) == 4;
+}
+
+FLAC__bool write_little_endian_uint64(FILE *f, FLAC__uint64 val)
+{
+	FLAC__byte *b = (FLAC__byte*)(&val);
+	if(is_big_endian_host_) {
+		FLAC__byte tmp;
+		tmp = b[7]; b[7] = b[0]; b[0] = tmp;
+		tmp = b[6]; b[6] = b[1]; b[1] = tmp;
+		tmp = b[5]; b[5] = b[2]; b[2] = tmp;
+		tmp = b[4]; b[4] = b[3]; b[3] = tmp;
+	}
+	return flac__utils_fwrite(b, 1, 8, f) == 8;
+}
+
+FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 val)
+{
+	FLAC__byte *b = (FLAC__byte*)(&val);
+	if(!is_big_endian_host_) {
+		FLAC__byte tmp;
+		tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+	}
+	return flac__utils_fwrite(b, 1, 2, f) == 2;
+}
+
+FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 val)
+{
+	FLAC__byte *b = (FLAC__byte*)(&val);
+	if(!is_big_endian_host_) {
+		FLAC__byte tmp;
+		tmp = b[3]; b[3] = b[0]; b[0] = tmp;
+		tmp = b[2]; b[2] = b[1]; b[1] = tmp;
+	}
+	return flac__utils_fwrite(b, 1, 4, f) == 4;
+}
+
+FLAC__bool write_sane_extended(FILE *f, uint32_t val)
+	/* Write to 'f' a SANE extended representation of 'val'.  Return false if
+	* the write succeeds; return true otherwise.
+	*
+	* SANE extended is an 80-bit IEEE-754 representation with sign bit, 15 bits
+	* of exponent, and 64 bits of significand (mantissa).  Unlike most IEEE-754
+	* representations, it does not imply a 1 above the MSB of the significand.
+	*
+	* Preconditions:
+	*  val!=0U
+	*/
+{
+	uint32_t shift, exponent;
+
+	FLAC__ASSERT(val!=0U); /* handling 0 would require a special case */
+
+	for(shift= 0U; (val>>(31-shift))==0U; ++shift)
+		;
+	val<<= shift;
+	exponent= 63U-(shift+32U); /* add 32 for unused second word */
+
+	if(!write_big_endian_uint16(f, (FLAC__uint16)(exponent+0x3FFF)))
+		return false;
+	if(!write_big_endian_uint32(f, val))
+		return false;
+	if(!write_big_endian_uint32(f, 0)) /* unused second word */
+		return false;
+
+	return true;
+}
+
+FLAC__bool fixup_iff_headers(DecoderSession *d)
+{
+	const char *fmt_desc =
+		d->format==FORMAT_WAVE? "WAVE" :
+		d->format==FORMAT_WAVE64? "Wave64" :
+		d->format==FORMAT_RF64? "RF64" :
+		"AIFF";
+	FILE *f = flac_fopen(d->outfilename, "r+b"); /* stream is positioned at beginning of file */
+
+	if(0 == f) {
+		flac__utils_printf(stderr, 1, "ERROR, couldn't open file %s while fixing up %s chunk size: %s\n", d->outfilename, fmt_desc, strerror(errno));
+		return false;
+	}
+
+	if(!write_iff_headers(f, d, d->samples_processed)) {
+		fclose(f);
+		return false;
+	}
+
+	fclose(f);
+	return true;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	DecoderSession *decoder_session = (DecoderSession*)client_data;
+	FILE *fout = decoder_session->fout;
+	const uint32_t bps = frame->header.bits_per_sample, channels = frame->header.channels;
+	const uint32_t shift = (decoder_session->format != FORMAT_RAW && (bps%8))? 8-(bps%8): 0;
+	FLAC__bool is_big_endian = (
+		decoder_session->format == FORMAT_AIFF || decoder_session->format == FORMAT_AIFF_C ? true : (
+		decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 ? false :
+		decoder_session->is_big_endian
+	));
+	FLAC__bool is_unsigned_samples = (
+		decoder_session->format == FORMAT_AIFF || decoder_session->format == FORMAT_AIFF_C ? false : (
+		decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 ? bps<=8 :
+		decoder_session->is_unsigned_samples
+	));
+	uint32_t wide_samples = frame->header.blocksize, wide_sample, sample, channel;
+	uint32_t frame_bytes = 0;
+
+	static union
+	{	/* The arrays defined within this union are all the same size. */
+		FLAC__int8	 s8buffer	[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)]; /* WATCHOUT: can be up to 2 megs */
+		FLAC__uint8  u8buffer	[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)];
+		FLAC__int16  s16buffer	[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int16)];
+		FLAC__uint16 u16buffer	[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int16)];
+		FLAC__int32  s32buffer	[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS];
+		FLAC__uint32 u32buffer	[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS];
+	} ubuf;
+
+	size_t bytes_to_write = 0;
+
+	(void)decoder;
+
+	if(decoder_session->abort_flag)
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+	/* sanity-check the bits-per-sample */
+	if(decoder_session->bps) {
+		if(bps != decoder_session->bps) {
+			if(decoder_session->got_stream_info)
+				flac__utils_printf(stderr, 1, "%s: ERROR, bits-per-sample is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, bps, decoder_session->bps);
+			else
+				flac__utils_printf(stderr, 1, "%s: ERROR, bits-per-sample is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, bps, decoder_session->bps);
+			if(!decoder_session->continue_through_decode_errors)
+				return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+	else {
+		/* must not have gotten STREAMINFO, save the bps from the frame header */
+		FLAC__ASSERT(!decoder_session->got_stream_info);
+		decoder_session->bps = bps;
+	}
+
+	/* sanity-check the #channels */
+	if(decoder_session->channels) {
+		if(channels != decoder_session->channels) {
+			if(decoder_session->got_stream_info)
+				flac__utils_printf(stderr, 1, "%s: ERROR, channels is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, channels, decoder_session->channels);
+			else
+				flac__utils_printf(stderr, 1, "%s: ERROR, channels is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, channels, decoder_session->channels);
+			if(!decoder_session->continue_through_decode_errors)
+				return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+	else {
+		/* must not have gotten STREAMINFO, save the #channels from the frame header */
+		FLAC__ASSERT(!decoder_session->got_stream_info);
+		decoder_session->channels = channels;
+	}
+
+	/* sanity-check the sample rate */
+	if(decoder_session->sample_rate) {
+		if(frame->header.sample_rate != decoder_session->sample_rate) {
+			if(decoder_session->got_stream_info)
+				flac__utils_printf(stderr, 1, "%s: ERROR, sample rate is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, frame->header.sample_rate, decoder_session->sample_rate);
+			else
+				flac__utils_printf(stderr, 1, "%s: ERROR, sample rate is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, frame->header.sample_rate, decoder_session->sample_rate);
+			if(!decoder_session->continue_through_decode_errors)
+				return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+	else {
+		/* must not have gotten STREAMINFO, save the sample rate from the frame header */
+		FLAC__ASSERT(!decoder_session->got_stream_info);
+		decoder_session->sample_rate = frame->header.sample_rate;
+	}
+
+	/*
+	 * limit the number of samples to accept based on --until
+	 */
+	FLAC__ASSERT(!decoder_session->skip_specification->is_relative);
+	/* if we never got the total_samples from the metadata, the skip and until specs would never have been canonicalized, so protect against that: */
+	if(decoder_session->skip_specification->is_relative) {
+		if(decoder_session->skip_specification->value.samples == 0) /* special case for when no --skip was given */
+			decoder_session->skip_specification->is_relative = false; /* convert to our meaning of beginning-of-stream */
+		else {
+			flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --skip because the total sample count was not found in the metadata\n", decoder_session->inbasefilename);
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+	if(decoder_session->until_specification->is_relative) {
+		if(decoder_session->until_specification->value.samples == 0) /* special case for when no --until was given */
+			decoder_session->until_specification->is_relative = false; /* convert to our meaning of end-of-stream */
+		else {
+			flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until because the total sample count was not found in the metadata\n", decoder_session->inbasefilename);
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+	FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0);
+	FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0);
+	if(decoder_session->until_specification->value.samples > 0) {
+		const FLAC__uint64 skip = (FLAC__uint64)decoder_session->skip_specification->value.samples;
+		const FLAC__uint64 until = (FLAC__uint64)decoder_session->until_specification->value.samples;
+		const FLAC__uint64 input_samples_passed = skip + decoder_session->samples_processed;
+		FLAC__ASSERT(until >= input_samples_passed);
+		if(input_samples_passed + wide_samples > until)
+			wide_samples = (uint32_t)(until - input_samples_passed);
+		if (wide_samples == 0) {
+			decoder_session->abort_flag = true;
+			decoder_session->aborting_due_to_until = true;
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+
+	if(decoder_session->analysis_mode) {
+		FLAC__uint64 dpos;
+		FLAC__stream_decoder_get_decode_position(decoder_session->decoder, &dpos);
+		frame_bytes = (uint32_t)(dpos-decoder_session->decode_position);
+		decoder_session->decode_position = dpos;
+	}
+
+	if(wide_samples > 0) {
+		decoder_session->samples_processed += wide_samples;
+		decoder_session->frame_counter++;
+
+		if(!(decoder_session->frame_counter & 0x1ff))
+			print_stats(decoder_session);
+
+		if(decoder_session->analysis_mode) {
+			flac__analyze_frame(frame, decoder_session->frame_counter-1, decoder_session->decode_position-frame_bytes, frame_bytes, decoder_session->aopts, fout);
+		}
+		else if(!decoder_session->test_only) {
+			if(shift && !decoder_session->replaygain.apply) {
+				for(wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+					for(channel = 0; channel < channels; channel++)
+						((uint32_t **)buffer)[channel][wide_sample] <<= shift;/*@@@@@@un-const'ing the buffer is hacky but safe*/
+			}
+			if(decoder_session->replaygain.apply) {
+				bytes_to_write = FLAC__replaygain_synthesis__apply_gain(
+					ubuf.u8buffer,
+					!is_big_endian,
+					is_unsigned_samples,
+					buffer,
+					wide_samples,
+					channels,
+					bps, /* source_bps */
+					bps+shift, /* target_bps */
+					decoder_session->replaygain.scale,
+					decoder_session->replaygain.spec.limiter == RGSS_LIMIT__HARD, /* hard_limit */
+					decoder_session->replaygain.spec.noise_shaping != NOISE_SHAPING_NONE, /* do_dithering */
+					&decoder_session->replaygain.dither_context
+				);
+			}
+			/* first some special code for common cases */
+			else if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 2 && bps+shift == 16) {
+				FLAC__int16 *buf1_ = ubuf.s16buffer + 1;
+				if(is_big_endian)
+					memcpy(ubuf.s16buffer, ((FLAC__byte*)(buffer[0]))+2, sizeof(FLAC__int32) * wide_samples - 2);
+				else
+					memcpy(ubuf.s16buffer, buffer[0], sizeof(FLAC__int32) * wide_samples);
+				for(sample = 0; sample < wide_samples; sample++, buf1_+=2)
+					*buf1_ = (FLAC__int16)buffer[1][sample];
+				bytes_to_write = 4 * sample;
+			}
+			else if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 1 && bps+shift == 16) {
+				FLAC__int16 *buf1_ = ubuf.s16buffer;
+				for(sample = 0; sample < wide_samples; sample++)
+					*buf1_++ = (FLAC__int16)buffer[0][sample];
+				bytes_to_write = 2 * sample;
+			}
+			/* generic code for the rest */
+			else if(bps+shift == 16) {
+				if(is_unsigned_samples) {
+					if(channels == 2) {
+						for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+							ubuf.u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000);
+							ubuf.u16buffer[sample++] = (FLAC__uint16)(buffer[1][wide_sample] + 0x8000);
+						}
+					}
+					else if(channels == 1) {
+						for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+							ubuf.u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000);
+					}
+					else { /* works for any 'channels' but above flavors are faster for 1 and 2 */
+						for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+							for(channel = 0; channel < channels; channel++, sample++)
+								ubuf.u16buffer[sample] = (FLAC__uint16)(buffer[channel][wide_sample] + 0x8000);
+					}
+				}
+				else {
+					if(channels == 2) {
+						for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+							ubuf.s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
+							ubuf.s16buffer[sample++] = (FLAC__int16)(buffer[1][wide_sample]);
+						}
+					}
+					else if(channels == 1) {
+						for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+							ubuf.s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
+					}
+					else { /* works for any 'channels' but above flavors are faster for 1 and 2 */
+						for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+							for(channel = 0; channel < channels; channel++, sample++)
+								ubuf.s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]);
+					}
+				}
+				if(is_big_endian != is_big_endian_host_) {
+					uint8_t tmp;
+					const uint32_t bytes = sample * 2;
+					uint32_t b;
+					for(b = 0; b < bytes; b += 2) {
+						tmp = ubuf.u8buffer[b];
+						ubuf.u8buffer[b] = ubuf.u8buffer[b+1];
+						ubuf.u8buffer[b+1] = tmp;
+					}
+				}
+				bytes_to_write = 2 * sample;
+			}
+			else if(bps+shift == 24) {
+				if(is_unsigned_samples) {
+					for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+						for(channel = 0; channel < channels; channel++, sample++)
+							ubuf.u32buffer[sample] = buffer[channel][wide_sample] + 0x800000;
+				}
+				else {
+					for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+						for(channel = 0; channel < channels; channel++, sample++)
+							ubuf.s32buffer[sample] = buffer[channel][wide_sample];
+				}
+				if(is_big_endian != is_big_endian_host_) {
+					uint8_t tmp;
+					const uint32_t bytes = sample * 4;
+					uint32_t b;
+					for(b = 0; b < bytes; b += 4) {
+						tmp = ubuf.u8buffer[b];
+						ubuf.u8buffer[b] = ubuf.u8buffer[b+3];
+						ubuf.u8buffer[b+3] = tmp;
+						tmp = ubuf.u8buffer[b+1];
+						ubuf.u8buffer[b+1] = ubuf.u8buffer[b+2];
+						ubuf.u8buffer[b+2] = tmp;
+					}
+				}
+				if(is_big_endian) {
+					uint32_t b, lbyte;
+					const uint32_t bytes = sample * 4;
+					for(lbyte = b = 0; b < bytes; ) {
+						b++;
+						ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+						ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+						ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+					}
+				}
+				else {
+					uint32_t b, lbyte;
+					const uint32_t bytes = sample * 4;
+					for(lbyte = b = 0; b < bytes; ) {
+						ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+						ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+						ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+						b++;
+					}
+				}
+				bytes_to_write = 3 * sample;
+			}
+			else if(bps+shift == 8) {
+				if(is_unsigned_samples) {
+					for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+						for(channel = 0; channel < channels; channel++, sample++)
+							ubuf.u8buffer[sample] = (FLAC__uint8)(buffer[channel][wide_sample] + 0x80);
+				}
+				else {
+					for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+						for(channel = 0; channel < channels; channel++, sample++)
+							ubuf.s8buffer[sample] = (FLAC__int8)(buffer[channel][wide_sample]);
+				}
+				bytes_to_write = sample;
+			}
+			else {
+				FLAC__ASSERT(0);
+				/* double protection */
+				decoder_session->abort_flag = true;
+				return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+			}
+		}
+	}
+	if(bytes_to_write > 0) {
+		if(flac__utils_fwrite(ubuf.u8buffer, 1, bytes_to_write, fout) != bytes_to_write) {
+			/* if a pipe closed when writing to stdout, we let it go without an error message */
+			if(errno == EPIPE && decoder_session->fout == stdout)
+				decoder_session->aborting_due_to_until = true;
+			decoder_session->abort_flag = true;
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	DecoderSession *decoder_session = (DecoderSession*)client_data;
+
+	if(decoder_session->analysis_mode)
+		FLAC__stream_decoder_get_decode_position(decoder, &decoder_session->decode_position);
+
+	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		FLAC__uint64 skip, until;
+		decoder_session->got_stream_info = true;
+		decoder_session->has_md5sum = memcmp(metadata->data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16);
+		decoder_session->bps = metadata->data.stream_info.bits_per_sample;
+		decoder_session->channels = metadata->data.stream_info.channels;
+		decoder_session->sample_rate = metadata->data.stream_info.sample_rate;
+
+		flac__utils_canonicalize_skip_until_specification(decoder_session->skip_specification, decoder_session->sample_rate);
+		FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0);
+		skip = (FLAC__uint64)decoder_session->skip_specification->value.samples;
+
+		/* remember, metadata->data.stream_info.total_samples can be 0, meaning 'unknown' */
+		if(metadata->data.stream_info.total_samples > 0 && skip >= metadata->data.stream_info.total_samples) {
+			flac__utils_printf(stderr, 1, "%s: ERROR trying to --skip more samples than in stream\n", decoder_session->inbasefilename);
+			decoder_session->abort_flag = true;
+			return;
+		}
+		else if(metadata->data.stream_info.total_samples == 0 && skip > 0) {
+			flac__utils_printf(stderr, 1, "%s: ERROR, can't --skip when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename);
+			decoder_session->abort_flag = true;
+			return;
+		}
+		FLAC__ASSERT(skip == 0 || 0 == decoder_session->cue_specification);
+		decoder_session->total_samples = metadata->data.stream_info.total_samples - skip;
+
+		/* note that we use metadata->data.stream_info.total_samples instead of decoder_session->total_samples */
+		if(!canonicalize_until_specification(decoder_session->until_specification, decoder_session->inbasefilename, decoder_session->sample_rate, skip, metadata->data.stream_info.total_samples)) {
+			decoder_session->abort_flag = true;
+			return;
+		}
+		FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0);
+		until = (FLAC__uint64)decoder_session->until_specification->value.samples;
+
+		if(until > 0) {
+			FLAC__ASSERT(decoder_session->total_samples != 0);
+			FLAC__ASSERT(0 == decoder_session->cue_specification);
+			decoder_session->total_samples -= (metadata->data.stream_info.total_samples - until);
+		}
+
+		if(decoder_session->format == FORMAT_RAW && ((decoder_session->bps % 8) != 0  || decoder_session->bps < 4 || decoder_session->bps > 24)) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 8/16/24 for raw format output\n", decoder_session->inbasefilename, decoder_session->bps);
+			decoder_session->abort_flag = true;
+			return;
+		}
+
+		if(decoder_session->bps < 4 || decoder_session->bps > 24) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 4-24\n", decoder_session->inbasefilename, decoder_session->bps);
+			decoder_session->abort_flag = true;
+			return;
+		}
+	}
+	else if(metadata->type == FLAC__METADATA_TYPE_CUESHEET) {
+		/* remember, at this point, decoder_session->total_samples can be 0, meaning 'unknown' */
+		if(decoder_session->total_samples == 0) {
+			flac__utils_printf(stderr, 1, "%s: ERROR can't use --cue when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename);
+			decoder_session->abort_flag = true;
+			return;
+		}
+
+		flac__utils_canonicalize_cue_specification(decoder_session->cue_specification, &metadata->data.cue_sheet, decoder_session->total_samples, decoder_session->skip_specification, decoder_session->until_specification);
+
+		FLAC__ASSERT(!decoder_session->skip_specification->is_relative);
+		FLAC__ASSERT(decoder_session->skip_specification->value_is_samples);
+
+		FLAC__ASSERT(!decoder_session->until_specification->is_relative);
+		FLAC__ASSERT(decoder_session->until_specification->value_is_samples);
+
+		FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0);
+		FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0);
+		FLAC__ASSERT((FLAC__uint64)decoder_session->until_specification->value.samples <= decoder_session->total_samples);
+		FLAC__ASSERT(decoder_session->skip_specification->value.samples <= decoder_session->until_specification->value.samples);
+
+		decoder_session->total_samples = decoder_session->until_specification->value.samples - decoder_session->skip_specification->value.samples;
+	}
+	else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+		if (decoder_session->replaygain.spec.apply) {
+			double reference, gain, peak;
+			if (!(decoder_session->replaygain.apply = grabbag__replaygain_load_from_vorbiscomment(metadata, decoder_session->replaygain.spec.use_album_gain, /*strict=*/false, &reference, &gain, &peak))) {
+				flac__utils_printf(stderr, 1, "%s: WARNING: can't get %s (or even %s) ReplayGain tags\n", decoder_session->inbasefilename, decoder_session->replaygain.spec.use_album_gain? "album":"track", decoder_session->replaygain.spec.use_album_gain? "track":"album");
+				if(decoder_session->treat_warnings_as_errors) {
+					decoder_session->abort_flag = true;
+					return;
+				}
+			}
+			else {
+				const char *ls[] = { "no", "peak", "hard" };
+				const char *ns[] = { "no", "low", "medium", "high" };
+				decoder_session->replaygain.scale = grabbag__replaygain_compute_scale_factor(peak, gain, decoder_session->replaygain.spec.preamp, decoder_session->replaygain.spec.limiter == RGSS_LIMIT__PEAK);
+				FLAC__ASSERT(decoder_session->bps > 0 && decoder_session->bps <= 32);
+				FLAC__replaygain_synthesis__init_dither_context(&decoder_session->replaygain.dither_context, decoder_session->bps, decoder_session->replaygain.spec.noise_shaping);
+				flac__utils_printf(stderr, 1, "%s: INFO: applying %s ReplayGain (gain=%0.2fdB+preamp=%0.1fdB, %s noise shaping, %s limiting) to output\n", decoder_session->inbasefilename, decoder_session->replaygain.spec.use_album_gain? "album":"track", gain, decoder_session->replaygain.spec.preamp, ns[decoder_session->replaygain.spec.noise_shaping], ls[decoder_session->replaygain.spec.limiter]);
+				flac__utils_printf(stderr, 1, "%s: WARNING: applying ReplayGain is not lossless\n", decoder_session->inbasefilename);
+				/* don't check if(decoder_session->treat_warnings_as_errors) because the user explicitly asked for it */
+			}
+		}
+		(void)flac__utils_get_channel_mask_tag(metadata, &decoder_session->channel_mask);
+	}
+}
+
+void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	DecoderSession *decoder_session = (DecoderSession*)client_data;
+	(void)decoder;
+	if(!decoder_session->error_callback_suppress_messages) {
+		stats_print_name(1, decoder_session->inbasefilename);
+		flac__utils_printf(stderr, 1, "*** Got error code %d:%s\n", status, FLAC__StreamDecoderErrorStatusString[status]);
+	}
+	if(!decoder_session->continue_through_decode_errors) {
+		/* if we got a sync error while looking for metadata, either it's not a FLAC file (more likely) or the file is corrupted */
+		if(
+			!decoder_session->error_callback_suppress_messages &&
+			status == FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC &&
+			FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+		) {
+			flac__utils_printf(stderr, 1,
+				"\n"
+				"The input file is either not a FLAC file or is corrupted.  If you are\n"
+				"convinced it is a FLAC file, you can rerun the same command and add the\n"
+				"-F parameter to try and recover as much as possible from the file.\n"
+			);
+			decoder_session->error_callback_suppress_messages = true;
+		}
+		else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+			decoder_session->aborting_due_to_unparseable = true;
+		decoder_session->abort_flag = true;
+	}
+}
+
+void print_error_with_init_status(const DecoderSession *d, const char *message, FLAC__StreamDecoderInitStatus init_status)
+{
+	const int ilen = strlen(d->inbasefilename) + 1;
+
+	flac__utils_printf(stderr, 1, "\n%s: %s\n", d->inbasefilename, message);
+
+	flac__utils_printf(stderr, 1, "%*s init status = %s\n", ilen, "", FLAC__StreamDecoderInitStatusString[init_status]);
+
+	/* print out some more info for some errors: */
+	if (init_status == FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE) {
+		flac__utils_printf(stderr, 1,
+			"\n"
+			"An error occurred opening the input file; it is likely that it does not exist\n"
+			"or is not readable.\n"
+		);
+	}
+}
+
+void print_error_with_state(const DecoderSession *d, const char *message)
+{
+	const int ilen = strlen(d->inbasefilename) + 1;
+
+	flac__utils_printf(stderr, 1, "\n%s: %s\n", d->inbasefilename, message);
+	flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", FLAC__stream_decoder_get_resolved_state_string(d->decoder));
+
+	/* print out some more info for some errors: */
+	if (d->aborting_due_to_unparseable) {
+		flac__utils_printf(stderr, 1,
+			"\n"
+			"The FLAC stream may have been created by a more advanced encoder.  Try\n"
+			"  metaflac --show-vendor-tag %s\n"
+			"If the version number is greater than %s, this decoder is probably\n"
+			"not able to decode the file.  If the version number is not, the file\n"
+			"may be corrupted, or you may have found a bug.  In this case please\n"
+			"submit a bug report to\n"
+			"    https://sourceforge.net/p/flac/bugs/\n"
+			"Make sure to use the \"Monitor\" feature to monitor the bug status.\n",
+			d->inbasefilename, FLAC__VERSION_STRING
+		);
+	}
+}
+
+void print_stats(const DecoderSession *decoder_session)
+{
+	if(flac__utils_verbosity_ >= 2) {
+		const double progress = (double)decoder_session->samples_processed / (double)decoder_session->total_samples * 100.0;
+
+		if(decoder_session->total_samples > 0) {
+			if ((uint32_t)floor(progress + 0.5) == 100)
+				return;
+
+			stats_print_name(2, decoder_session->inbasefilename);
+			stats_print_info(2, "%s%u%% complete",
+				decoder_session->test_only? "testing, " : decoder_session->analysis_mode? "analyzing, " : "",
+				(uint32_t)floor(progress + 0.5)
+			);
+		}
+		else {
+			stats_print_name(2, decoder_session->inbasefilename);
+			stats_print_info(2, "%s %" PRIu64 " samples",
+				decoder_session->test_only? "tested" : decoder_session->analysis_mode? "analyzed" : "wrote",
+				decoder_session->samples_processed
+			);
+		}
+	}
+}
diff --git a/src/flac/decode.h b/src/flac/decode.h
new file mode 100644
index 0000000..6a90bfc
--- /dev/null
+++ b/src/flac/decode.h
@@ -0,0 +1,71 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__decode_h
+#define flac__decode_h
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "analyze.h"
+#include "foreign_metadata.h"
+#include "utils.h"
+#include "share/replaygain_synthesis.h"
+
+
+typedef struct {
+	FLAC__bool apply;
+	FLAC__bool use_album_gain; /* false => use track gain */
+	enum { RGSS_LIMIT__NONE, RGSS_LIMIT__PEAK, RGSS_LIMIT__HARD} limiter;
+	NoiseShaping noise_shaping;
+	double preamp;
+} replaygain_synthesis_spec_t;
+
+typedef struct {
+	FLAC__bool treat_warnings_as_errors;
+	FLAC__bool continue_through_decode_errors;
+	replaygain_synthesis_spec_t replaygain_synthesis_spec;
+#if FLAC__HAS_OGG
+	FLAC__bool is_ogg;
+	FLAC__bool use_first_serial_number;
+	long serial_number;
+#endif
+	utils__SkipUntilSpecification skip_specification;
+	utils__SkipUntilSpecification until_specification;
+	FLAC__bool has_cue_specification;
+	utils__CueSpecification cue_specification;
+	FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */
+
+	FileFormat format;
+	union {
+		struct {
+			FLAC__bool is_big_endian;
+			FLAC__bool is_unsigned_samples;
+		} raw;
+		struct {
+			foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */
+		} iff;
+	} format_options;
+} decode_options_t;
+
+/* outfile == 0 => test only */
+int flac__decode_file(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, decode_options_t options);
+
+#endif
diff --git a/src/flac/encode.c b/src/flac/encode.c
new file mode 100644
index 0000000..a7fbfdf
--- /dev/null
+++ b/src/flac/encode.c
@@ -0,0 +1,2898 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <limits.h> /* for LONG_MAX */
+#include <math.h> /* for floor() */
+#include <stdio.h> /* for FILE etc. */
+#include <stdlib.h> /* for malloc */
+#include <string.h> /* for strcmp(), strerror() */
+#include <sys/stat.h>
+#include "FLAC/all.h"
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "share/private.h"
+#include "share/safe_str.h"
+#include "encode.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/* this MUST be >= 588 so that sector aligning can take place with one read */
+/* this MUST be < 2^sizeof(size_t) / ( FLAC__MAX_CHANNELS * (FLAC__MAX_BITS_PER_SAMPLE/8) ) */
+#define CHUNK_OF_SAMPLES 2048
+
+typedef struct {
+	uint32_t sample_rate;
+	uint32_t channels;
+	uint32_t bits_per_sample; /* width of sample point, including 'shift' bits, valid bps is bits_per_sample-shift */
+	uint32_t shift; /* # of LSBs samples have been shifted left by */
+	uint32_t bytes_per_wide_sample; /* for convenience, always == channels*((bps+7)/8), or 0 if N/A to input format (like FLAC) */
+	FLAC__bool is_unsigned_samples;
+	FLAC__bool is_big_endian;
+	FLAC__uint32 channel_mask;
+} SampleInfo;
+
+/* this is the client_data attached to the FLAC decoder when encoding from a FLAC file */
+typedef struct {
+	FLAC__off_t filesize;
+	const FLAC__byte *lookahead;
+	uint32_t lookahead_length;
+	size_t num_metadata_blocks;
+	FLAC__StreamMetadata *metadata_blocks[1024]; /*@@@ BAD MAGIC number */
+	FLAC__uint64 samples_left_to_process;
+	FLAC__bool fatal_error;
+} FLACDecoderData;
+
+typedef struct {
+#if FLAC__HAS_OGG
+	FLAC__bool use_ogg;
+#endif
+	FLAC__bool verify;
+	FLAC__bool is_stdout;
+	FLAC__bool outputfile_opened; /* true if we successfully opened the output file and we want it to be deleted if there is an error */
+	const char *inbasefilename;
+	const char *infilename;
+	const char *outfilename;
+
+	FLAC__bool treat_warnings_as_errors;
+	FLAC__bool continue_through_decode_errors;
+	FLAC__bool replay_gain;
+	FLAC__uint64 total_samples_to_encode; /* (i.e. "wide samples" aka "sample frames") WATCHOUT: may be 0 to mean 'unknown' */
+	FLAC__uint64 unencoded_size; /* an estimate of the input size, only used in the progress indicator */
+	FLAC__uint64 bytes_written;
+	FLAC__uint64 samples_written;
+	uint32_t stats_frames_interval;
+	uint32_t old_frames_written;
+
+	SampleInfo info;
+
+	FileFormat format;
+	union {
+		struct {
+			FLAC__uint64 data_bytes;
+		} iff;
+		struct {
+			FLAC__StreamDecoder *decoder;
+			FLACDecoderData client_data;
+		} flac;
+	} fmt;
+
+	FLAC__StreamEncoder *encoder;
+
+	FILE *fin;
+	FLAC__StreamMetadata *seek_table_template;
+	double progress, compression_ratio;
+} EncoderSession;
+
+const int FLAC_ENCODE__DEFAULT_PADDING = 8192;
+
+static FLAC__bool is_big_endian_host_;
+
+#define UBUFFER_INT8_SIZE 0x10000
+
+static union {
+	FLAC__int8 s8[UBUFFER_INT8_SIZE];
+	FLAC__uint8 u8[UBUFFER_INT8_SIZE];
+	FLAC__int16 s16[UBUFFER_INT8_SIZE/2];
+	FLAC__uint16 u16[UBUFFER_INT8_SIZE/2];
+} ubuffer;
+
+
+static FLAC__int32 in_[FLAC__MAX_CHANNELS][CHUNK_OF_SAMPLES];
+static FLAC__int32 *input_[FLAC__MAX_CHANNELS];
+
+
+/*
+ * local routines
+ */
+static FLAC__bool EncoderSession_construct(EncoderSession *e, encode_options_t options, FLAC__off_t infilesize, FILE *infile, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length);
+static void EncoderSession_destroy(EncoderSession *e);
+static int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int info_align_zero, foreign_metadata_t *foreign_metadata, FLAC__bool error_on_compression_fail);
+static int EncoderSession_finish_error(EncoderSession *e);
+static FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options);
+static FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], uint32_t samples);
+static FLAC__bool EncoderSession_format_is_iff(const EncoderSession *e);
+static FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e);
+static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input);
+static FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, uint32_t num_metadata);
+static FLAC__bool format_input(FLAC__int32 *dest[], uint32_t wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, uint32_t channels, uint32_t bps, uint32_t shift, size_t *channel_map);
+static void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data);
+static FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool flac_decoder_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data);
+static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+static void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+static FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors);
+static void print_stats(const EncoderSession *encoder_session);
+static void print_error_with_init_status(const EncoderSession *e, const char *message, FLAC__StreamEncoderInitStatus init_status);
+static void print_error_with_state(const EncoderSession *e, const char *message);
+static void print_verify_error(EncoderSession *e);
+static FLAC__bool read_bytes(FILE *f, FLAC__byte *buf, size_t n, FLAC__bool eof_ok, const char *fn);
+static FLAC__bool read_uint16(FILE *f, FLAC__bool big_endian, FLAC__uint16 *val, const char *fn);
+static FLAC__bool read_uint32(FILE *f, FLAC__bool big_endian, FLAC__uint32 *val, const char *fn);
+static FLAC__bool read_uint64(FILE *f, FLAC__bool big_endian, FLAC__uint64 *val, const char *fn);
+static FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, const char *fn);
+static FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset);
+static uint32_t count_channel_mask_bits(FLAC__uint32 mask);
+#if 0
+static FLAC__uint32 limit_channel_mask(FLAC__uint32 mask, uint32_t channels);
+#endif
+
+static FLAC__bool get_sample_info_raw(EncoderSession *e, encode_options_t options)
+{
+	e->info.sample_rate = options.format_options.raw.sample_rate;
+	e->info.channels = options.format_options.raw.channels;
+	e->info.bits_per_sample = options.format_options.raw.bps;
+	e->info.shift = 0;
+	e->info.bytes_per_wide_sample = options.format_options.raw.channels * ((options.format_options.raw.bps+7)/8);
+	e->info.is_unsigned_samples = options.format_options.raw.is_unsigned_samples;
+	e->info.is_big_endian = options.format_options.raw.is_big_endian;
+	e->info.channel_mask = 0;
+
+	return true;
+}
+
+static FLAC__bool get_sample_info_wave(EncoderSession *e, encode_options_t options)
+{
+	FLAC__bool got_fmt_chunk = false, got_data_chunk = false, got_ds64_chunk = false;
+	uint32_t sample_rate = 0, channels = 0, bps = 0, shift = 0;
+	FLAC__uint32 channel_mask = 0;
+	FLAC__uint64 ds64_data_size = 0;
+
+	e->info.is_unsigned_samples = false;
+	e->info.is_big_endian = false;
+
+	if(e->format == FORMAT_WAVE64) {
+		/*
+		 * lookahead[] already has "riff\x2E\x91\xCF\x11\xA5\xD6\x28\xDB", skip over remaining header
+		 */
+		if(!fskip_ahead(e->fin, 16+8+16-12)) { /* riff GUID + riff size + WAVE GUID - lookahead */
+			flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over remaining \"riff\" header\n", e->inbasefilename);
+			return false;
+		}
+	}
+	/* else lookahead[] already has "RIFFxxxxWAVE" or "RF64xxxxWAVE" */
+
+	while(!feof(e->fin) && !got_data_chunk) {
+		/* chunk IDs are 4 bytes for WAVE/RF64, 16 for Wave64 */
+		/* for WAVE/RF64 we want the 5th char zeroed so we can treat it like a C string */
+		char chunk_id[16] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
+
+		if(!read_bytes(e->fin, (FLAC__byte*)chunk_id, e->format==FORMAT_WAVE64?16:4, /*eof_ok=*/true, e->inbasefilename)) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", e->inbasefilename);
+			return false;
+		}
+		if(feof(e->fin))
+			break;
+
+		if(e->format == FORMAT_RF64 && !memcmp(chunk_id, "ds64", 4)) { /* RF64 64-bit sizes chunk */
+			FLAC__uint32 xx, data_bytes;
+
+			if(got_ds64_chunk) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'ds64' chunks\n", e->inbasefilename);
+				return false;
+			}
+			if(got_fmt_chunk) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: 'ds64' chunk appears after 'fmt ' or 'data' chunk\n", e->inbasefilename);
+				return false;
+			}
+
+			/* ds64 chunk size */
+			if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+				return false;
+			data_bytes = xx;
+			if(data_bytes < 28) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: non-standard 'ds64' chunk has length = %u\n", e->inbasefilename, (uint32_t)data_bytes);
+				return false;
+			}
+			if(data_bytes & 1) /* should never happen, but enforce WAVE alignment rules */
+				data_bytes++;
+
+			/* RIFF 64-bit size, lo/hi */
+			if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+				return false;
+			if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+				return false;
+
+			/* 'data' 64-bit size */
+			if(!read_uint64(e->fin, /*big_endian=*/false, &ds64_data_size, e->inbasefilename))
+				return false;
+
+			data_bytes -= 16;
+
+			/* skip any extra data in the ds64 chunk */
+			if(!fskip_ahead(e->fin, data_bytes)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra 'ds64' data\n", e->inbasefilename);
+				return false;
+			}
+
+			got_ds64_chunk = true;
+		}
+		else if(
+			!memcmp(chunk_id, "fmt ", 4) &&
+			(e->format!=FORMAT_WAVE64 || !memcmp(chunk_id, "fmt \xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16))
+		) { /* format chunk */
+			FLAC__uint16 x;
+			FLAC__uint32 xx, data_bytes;
+			FLAC__uint16 wFormatTag; /* wFormatTag word from the 'fmt ' chunk */
+
+			if(got_fmt_chunk) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'fmt ' chunks\n", e->inbasefilename);
+				return false;
+			}
+
+			/* see
+			 *   http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
+			 *   http://windowssdk.msdn.microsoft.com/en-us/library/ms713497.aspx
+			 *   http://msdn.microsoft.com/library/default.asp?url=/library/en-us/audio_r/hh/Audio_r/aud-prop_d40f094e-44f9-4baa-8a15-03e4fb369501.xml.asp
+			 *
+			 * WAVEFORMAT is
+			 * 4 byte: chunk size
+			 * 2 byte: format type: 1 for WAVE_FORMAT_PCM, 65534 for WAVE_FORMAT_EXTENSIBLE
+			 * 2 byte: # channels
+			 * 4 byte: sample rate (Hz)
+			 * 4 byte: avg bytes per sec
+			 * 2 byte: block align
+			 * 2 byte: bits per sample (not necessarily all significant)
+			 * WAVEFORMATEX adds
+			 * 2 byte: extension size in bytes (usually 0 for WAVEFORMATEX and 22 for WAVEFORMATEXTENSIBLE with PCM)
+			 * WAVEFORMATEXTENSIBLE adds
+			 * 2 byte: valid bits per sample
+			 * 4 byte: channel mask
+			 * 16 byte: subformat GUID, first 2 bytes have format type, 1 being PCM
+			 *
+			 * Current spec says WAVEFORMATEX with PCM must have bps == 8 or 16, or any multiple of 8 for WAVEFORMATEXTENSIBLE.
+			 * Lots of old broken WAVEs/apps have don't follow it, e.g. 20 bps but a block align of 3/6 for mono/stereo.
+			 *
+			 * Block align for WAVE_FORMAT_PCM or WAVE_FORMAT_EXTENSIBLE is also supposed to be channels*bps/8
+			 *
+			 * If the channel mask has more set bits than # of channels, the extra MSBs are ignored.
+			 * If the channel mask has less set bits than # of channels, the extra channels are unassigned to any speaker.
+			 *
+			 * Data is supposed to be uint32_t for bps <= 8 else signed.
+			 */
+
+			/* fmt chunk size */
+			if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+				return false;
+			data_bytes = xx;
+			if(e->format == FORMAT_WAVE64) {
+				/* other half of the size field should be 0 */
+				if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+					return false;
+				if(xx) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: freakishly large Wave64 'fmt ' chunk has length = 0x%08X%08X\n", e->inbasefilename, (uint32_t)xx, (uint32_t)data_bytes);
+					return false;
+				}
+				/* subtract size of header */
+				if (data_bytes < 16+8) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 'fmt ' chunk has length = 0x%08X%08X\n", e->inbasefilename, (uint32_t)xx, (uint32_t)data_bytes);
+					return false;
+				}
+				data_bytes -= (16+8);
+			}
+			if(data_bytes < 16) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: non-standard 'fmt ' chunk has length = %u\n", e->inbasefilename, (uint32_t)data_bytes);
+				return false;
+			}
+			if(e->format != FORMAT_WAVE64) {
+				if(data_bytes & 1) /* should never happen, but enforce WAVE alignment rules */
+					data_bytes++;
+			}
+			else { /* Wave64 */
+				data_bytes = (data_bytes+7) & (~7u); /* should never happen, but enforce Wave64 alignment rules */
+			}
+
+			/* format code */
+			if(!read_uint16(e->fin, /*big_endian=*/false, &wFormatTag, e->inbasefilename))
+				return false;
+			if(wFormatTag != 1 /*WAVE_FORMAT_PCM*/ && wFormatTag != 65534 /*WAVE_FORMAT_EXTENSIBLE*/) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: unsupported format type %u\n", e->inbasefilename, (uint32_t)wFormatTag);
+				return false;
+			}
+
+			/* number of channels */
+			if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+				return false;
+			channels = (uint32_t)x;
+
+			/* sample rate */
+			if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+				return false;
+			sample_rate = xx;
+
+			/* avg bytes per second (ignored) */
+			if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+				return false;
+			/* block align */
+			if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+				return false;
+
+			/* bits per sample */
+			if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+				return false;
+			bps = (uint32_t)x;
+
+			e->info.is_unsigned_samples = (bps <= 8);
+
+			if(wFormatTag == 1) {
+				if(bps != 8 && bps != 16) {
+					if(bps == 24 || bps == 32) {
+						/* let these slide with a warning since they're unambiguous */
+						flac__utils_printf(stderr, 1, "%s: WARNING: legacy WAVE file has format type %u but bits-per-sample=%u\n", e->inbasefilename, (uint32_t)wFormatTag, bps);
+						if(e->treat_warnings_as_errors)
+							return false;
+					}
+					else {
+						/* @@@ we could add an option to specify left- or right-justified blocks so we knew how to set 'shift' */
+						flac__utils_printf(stderr, 1, "%s: ERROR: legacy WAVE file has format type %u but bits-per-sample=%u\n", e->inbasefilename, (uint32_t)wFormatTag, bps);
+						return false;
+					}
+				}
+#if 0 /* @@@ reinstate once we can get an answer about whether the samples are left- or right-justified */
+				if((bps+7)/8 * channels == block_align) {
+					if(bps % 8) {
+						/* assume legacy file is byte aligned with some LSBs zero; this is double-checked in format_input() */
+						flac__utils_printf(stderr, 1, "%s: WARNING: legacy WAVE file (format type %d) has block alignment=%u, bits-per-sample=%u, channels=%u\n", e->inbasefilename, (uint32_t)wFormatTag, block_align, bps, channels);
+						if(e->treat_warnings_as_errors)
+							return false;
+						shift = 8 - (bps % 8);
+						bps += shift;
+					}
+					else
+						shift = 0;
+				}
+				else {
+					flac__utils_printf(stderr, 1, "%s: ERROR: illegal WAVE file (format type %d) has block alignment=%u, bits-per-sample=%u, channels=%u\n", e->inbasefilename, (uint32_t)wFormatTag, block_align, bps, channels);
+					return false;
+				}
+#else
+				shift = 0;
+#endif
+				if(channels > 2 && !options.channel_map_none) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: WAVE has >2 channels but is not WAVE_FORMAT_EXTENSIBLE; cannot assign channels\n", e->inbasefilename);
+					return false;
+				}
+				FLAC__ASSERT(data_bytes >= 16);
+				data_bytes -= 16;
+			}
+			else {
+				if(data_bytes < 40) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with size %u\n", e->inbasefilename, (uint32_t)data_bytes);
+					return false;
+				}
+				/* cbSize */
+				if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+					return false;
+				if(x < 22) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with cbSize %u\n", e->inbasefilename, (uint32_t)x);
+					return false;
+				}
+				/* valid bps */
+				if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+					return false;
+				if((uint32_t)x > bps) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with wValidBitsPerSample (%u) > wBitsPerSample (%u)\n", e->inbasefilename, (uint32_t)x, bps);
+					return false;
+				}
+				shift = bps - (uint32_t)x;
+				/* channel mask */
+				if(!read_uint32(e->fin, /*big_endian=*/false, &channel_mask, e->inbasefilename))
+					return false;
+				/* for mono/stereo and unassigned channels, we fake the mask */
+				if(channel_mask == 0) {
+					if(channels == 1)
+						channel_mask = 0x0004;
+					else if(channels == 2)
+						channel_mask = 0x0003;
+				}
+				/* set channel mapping */
+				/* FLAC order follows SMPTE and WAVEFORMATEXTENSIBLE but with fewer channels, which are: */
+				/* front left, front right, front center, LFE, back left, back right, back center, side left, side right */
+				/* the default mapping is sufficient for 1-8 channels */
+#if 0
+				/* @@@ example for dolby/vorbis order, for reference later in case it becomes important */
+				if(
+					options.channel_map_none ||
+					channel_mask == 0x0001 || /* 1 channel: (mono) */
+					channel_mask == 0x0003 || /* 2 channels: front left, front right */
+					channel_mask == 0x0033 || /* 4 channels: front left, front right, back left, back right */
+					channel_mask == 0x0603    /* 4 channels: front left, front right, side left, side right */
+				) {
+					/* keep default channel order */
+				}
+				else if(
+					channel_mask == 0x0007 || /* 3 channels: front left, front right, front center */
+					channel_mask == 0x0037 || /* 5 channels: front left, front right, front center, back left, back right */
+					channel_mask == 0x0607    /* 5 channels: front left, front right, front center, side left, side right */
+				) {
+					/* to dolby order: front left, center, front right [, surround left, surround right ] */
+					channel_map[1] = 2;
+					channel_map[2] = 1;
+				}
+				else if(
+					channel_mask == 0x003f || /* 6 channels: front left, front right, front center, LFE, back left, back right */
+					channel_mask == 0x060f || /* 6 channels: front left, front right, front center, LFE, side left, side right */
+					channel_mask == 0x070f || /* 7 channels: front left, front right, front center, LFE, back center, side left, side right */
+					channel_mask == 0x063f    /* 8 channels: front left, front right, front center, LFE, back left, back right, side left, side right */
+				) {
+					/* to dolby order: front left, center, front right, surround left, surround right, LFE */
+					channel_map[1] = 2;
+					channel_map[2] = 1;
+					channel_map[3] = 5;
+					channel_map[4] = 3;
+					channel_map[5] = 4;
+				}
+#else
+				if(
+					options.channel_map_none ||
+					channel_mask == 0x0001 || /* 1 channel: front left */
+					channel_mask == 0x0002 || /* 1 channel: front right */
+					channel_mask == 0x0004 || /* 1 channel: mono or front center */
+					channel_mask == 0x0003 || /* 2 channels: front left, front right */
+					channel_mask == 0x0007 || /* 3 channels: front left, front right, front center */
+					channel_mask == 0x0033 || /* 4 channels: front left, front right, back left, back right */
+					channel_mask == 0x0603 || /* 4 channels: front left, front right, side left, side right */
+					channel_mask == 0x0037 || /* 5 channels: front left, front right, front center, back left, back right */
+					channel_mask == 0x0607 || /* 5 channels: front left, front right, front center, side left, side right */
+					channel_mask == 0x003f || /* 6 channels: front left, front right, front center, LFE, back left, back right */
+					channel_mask == 0x060f || /* 6 channels: front left, front right, front center, LFE, side left, side right */
+					channel_mask == 0x070f || /* 7 channels: front left, front right, front center, LFE, back center, side left, side right */
+					channel_mask == 0x063f    /* 8 channels: front left, front right, front center, LFE, back left, back right, side left, side right */
+				) {
+					/* keep default channel order */
+				}
+#endif
+				else {
+					flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk with unsupported channel mask=0x%04X\n\nUse --channel-map=none option to encode the input\n", e->inbasefilename, (uint32_t)channel_mask);
+					return false;
+				}
+				if(!options.channel_map_none) {
+					if(count_channel_mask_bits(channel_mask) < channels) {
+						flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk: channel mask 0x%04X has unassigned channels (#channels=%u)\n", e->inbasefilename, (uint32_t)channel_mask, channels);
+						return false;
+					}
+#if 0
+					/* supporting this is too difficult with channel mapping; e.g. what if mask is 0x003f but #channels=4?
+					 * there would be holes in the order that would have to be filled in, or the mask would have to be
+					 * limited and the logic above rerun to see if it still fits into the FLAC mapping.
+					 */
+					else if(count_channel_mask_bits(channel_mask) > channels)
+						channel_mask = limit_channel_mask(channel_mask, channels);
+#else
+					else if(count_channel_mask_bits(channel_mask) > channels) {
+						flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk: channel mask 0x%04X has extra bits for non-existant channels (#channels=%u)\n", e->inbasefilename, (uint32_t)channel_mask, channels);
+						return false;
+					}
+#endif
+				}
+				/* first part of GUID */
+				if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+					return false;
+				if(x != 1) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: unsupported WAVEFORMATEXTENSIBLE chunk with non-PCM format %u\n", e->inbasefilename, (uint32_t)x);
+					return false;
+				}
+				data_bytes -= 26;
+			}
+
+			e->info.bytes_per_wide_sample = channels * (bps / 8);
+
+			/* skip any extra data in the fmt chunk */
+			if(!fskip_ahead(e->fin, data_bytes)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra 'fmt' data\n", e->inbasefilename);
+				return false;
+			}
+
+			got_fmt_chunk = true;
+		}
+		else if(
+			!memcmp(chunk_id, "data", 4) &&
+			(e->format!=FORMAT_WAVE64 || !memcmp(chunk_id, "data\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16))
+		) { /* data chunk */
+			FLAC__uint32 xx;
+			FLAC__uint64 data_bytes;
+
+			if(!got_fmt_chunk) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: got 'data' chunk before 'fmt' chunk\n", e->inbasefilename);
+				return false;
+			}
+
+			/* data size */
+			if(e->format != FORMAT_WAVE64) {
+				if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+					return false;
+				data_bytes = xx;
+			}
+			else { /* Wave64 */
+				if(!read_uint64(e->fin, /*big_endian=*/false, &data_bytes, e->inbasefilename))
+					return false;
+				/* subtract size of header */
+				if (data_bytes < 16+8) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 'data' chunk has length = 0x00000000%08X\n", e->inbasefilename, (uint32_t)data_bytes);
+					return false;
+				}
+				data_bytes -= (16+8);
+			}
+			if(e->format == FORMAT_RF64) {
+				if(!got_ds64_chunk) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: RF64 file has no 'ds64' chunk before 'data' chunk\n", e->inbasefilename);
+					return false;
+				}
+				if(data_bytes == 0xffffffff)
+					data_bytes = ds64_data_size;
+			}
+			if(options.ignore_chunk_sizes) {
+				FLAC__ASSERT(!options.sector_align);
+				if(data_bytes) {
+					flac__utils_printf(stderr, 1, "%s: WARNING: 'data' chunk has non-zero size, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id);
+					if(e->treat_warnings_as_errors)
+						return false;
+				}
+				data_bytes = (FLAC__uint64)0 - (FLAC__uint64)e->info.bytes_per_wide_sample; /* max out data_bytes; we'll use EOF as signal to stop reading */
+			}
+			else if(0 == data_bytes) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: 'data' chunk has size of 0\n", e->inbasefilename);
+				return false;
+			}
+
+			e->fmt.iff.data_bytes = data_bytes;
+
+			got_data_chunk = true;
+			break;
+		}
+		else {
+			FLAC__uint32 xx;
+			FLAC__uint64 skip;
+			if(!options.format_options.iff.foreign_metadata) {
+				if(e->format != FORMAT_WAVE64)
+					flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk '%s' (use --keep-foreign-metadata to keep)\n", e->inbasefilename, chunk_id);
+				else
+					flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X (use --keep-foreign-metadata to keep)\n",
+						e->inbasefilename,
+						(uint32_t)((const uint8_t *)chunk_id)[3],
+						(uint32_t)((const uint8_t *)chunk_id)[2],
+						(uint32_t)((const uint8_t *)chunk_id)[1],
+						(uint32_t)((const uint8_t *)chunk_id)[0],
+						(uint32_t)((const uint8_t *)chunk_id)[5],
+						(uint32_t)((const uint8_t *)chunk_id)[4],
+						(uint32_t)((const uint8_t *)chunk_id)[7],
+						(uint32_t)((const uint8_t *)chunk_id)[6],
+						(uint32_t)((const uint8_t *)chunk_id)[9],
+						(uint32_t)((const uint8_t *)chunk_id)[8],
+						(uint32_t)((const uint8_t *)chunk_id)[10],
+						(uint32_t)((const uint8_t *)chunk_id)[11],
+						(uint32_t)((const uint8_t *)chunk_id)[12],
+						(uint32_t)((const uint8_t *)chunk_id)[13],
+						(uint32_t)((const uint8_t *)chunk_id)[14],
+						(uint32_t)((const uint8_t *)chunk_id)[15]
+					);
+				if(e->treat_warnings_as_errors)
+					return false;
+			}
+
+			/* chunk size */
+			if(e->format != FORMAT_WAVE64) {
+				if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+					return false;
+				skip = xx;
+				skip += skip & 1;
+			}
+			else { /* Wave64 */
+				if(!read_uint64(e->fin, /*big_endian=*/false, &skip, e->inbasefilename))
+					return false;
+				skip = (skip+7) & (~(FLAC__uint64)7);
+				/* subtract size of header */
+				if (skip < 16+8) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 chunk has length = 0x00000000%08X\n", e->inbasefilename, (uint32_t)skip);
+					return false;
+				}
+				skip -= (16+8);
+			}
+			if(skip) {
+				if(!fskip_ahead(e->fin, skip)) {
+					flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over chunk\n", e->inbasefilename);
+					return false;
+				}
+			}
+		}
+	}
+
+	if(!got_fmt_chunk) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: didn't find fmt chunk\n", e->inbasefilename);
+		return false;
+	}
+	if(!got_data_chunk) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: didn't find data chunk\n", e->inbasefilename);
+		return false;
+	}
+
+	e->info.sample_rate = sample_rate;
+	e->info.channels = channels;
+	e->info.bits_per_sample = bps;
+	e->info.shift = shift;
+	e->info.channel_mask = channel_mask;
+
+	return true;
+}
+
+static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t options)
+{
+	FLAC__bool got_comm_chunk = false, got_ssnd_chunk = false;
+	uint32_t sample_rate = 0, channels = 0, bps = 0, shift = 0;
+	FLAC__uint64 sample_frames = 0;
+	FLAC__uint32 channel_mask = 0;
+
+	e->info.is_unsigned_samples = false;
+	e->info.is_big_endian = true;
+
+	/*
+	 * lookahead[] already has "FORMxxxxAIFF", do chunks
+	 */
+	while(!feof(e->fin) && !got_ssnd_chunk) {
+		char chunk_id[5] = { '\0', '\0', '\0', '\0', '\0' }; /* one extra byte for terminating NUL so we can also treat it like a C string */
+		if(!read_bytes(e->fin, (FLAC__byte*)chunk_id, 4, /*eof_ok=*/true, e->inbasefilename)) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", e->inbasefilename);
+			return false;
+		}
+		if(feof(e->fin))
+			break;
+
+		if(!memcmp(chunk_id, "COMM", 4)) { /* common chunk */
+			FLAC__uint16 x;
+			FLAC__uint32 xx;
+			uint64_t skip;
+			const FLAC__bool is_aifc = e->format == FORMAT_AIFF_C;
+			const FLAC__uint32 minimum_comm_size = (is_aifc? 22 : 18);
+
+			if(got_comm_chunk) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'COMM' chunks\n", e->inbasefilename);
+				return false;
+			}
+
+			/* COMM chunk size */
+			if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+				return false;
+			else if(xx < minimum_comm_size) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: non-standard %s 'COMM' chunk has length = %u\n", e->inbasefilename, is_aifc? "AIFF-C" : "AIFF", (uint32_t)xx);
+				return false;
+			}
+			else if(!is_aifc && xx != minimum_comm_size) {
+				flac__utils_printf(stderr, 1, "%s: WARNING: non-standard %s 'COMM' chunk has length = %u, expected %u\n", e->inbasefilename, is_aifc? "AIFF-C" : "AIFF", (uint32_t)xx, minimum_comm_size);
+				if(e->treat_warnings_as_errors)
+					return false;
+			}
+			skip = (xx-minimum_comm_size)+(xx & 1);
+
+			/* number of channels */
+			if(!read_uint16(e->fin, /*big_endian=*/true, &x, e->inbasefilename))
+				return false;
+			channels = (uint32_t)x;
+			if(channels > 2 && !options.channel_map_none) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u for AIFF\n", e->inbasefilename, channels);
+				return false;
+			}
+
+			/* number of sample frames */
+			if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+				return false;
+			sample_frames = xx;
+
+			/* bits per sample */
+			if(!read_uint16(e->fin, /*big_endian=*/true, &x, e->inbasefilename))
+				return false;
+			bps = (uint32_t)x;
+			shift = (bps%8)? 8-(bps%8) : 0; /* SSND data is always byte-aligned, left-justified but format_input() will double-check */
+			bps += shift;
+
+			/* sample rate */
+			if(!read_sane_extended(e->fin, &xx, e->inbasefilename))
+				return false;
+			sample_rate = xx;
+
+			/* check compression type for AIFF-C */
+			if(is_aifc) {
+				if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+					return false;
+				if(xx == 0x736F7774) /* "sowt" */
+					e->info.is_big_endian = false;
+				else if(xx == 0x4E4F4E45) /* "NONE" */
+					; /* nothing to do, we already default to big-endian */
+				else {
+					flac__utils_printf(stderr, 1, "%s: ERROR: can't handle AIFF-C compression type \"%c%c%c%c\"\n", e->inbasefilename, (char)(xx>>24), (char)((xx>>16)&8), (char)((xx>>8)&8), (char)(xx&8));
+					return false;
+				}
+			}
+
+			/* set channel mapping */
+			/* FLAC order follows SMPTE and WAVEFORMATEXTENSIBLE but with fewer channels, which are: */
+			/* front left, front right, center, LFE, back left, back right, surround left, surround right */
+			/* specs say the channel ordering is:
+			 *                             1     2   3   4   5   6
+			 * ___________________________________________________
+			 * 2         stereo            l     r
+			 * 3                           l     r   c
+			 * 4                           l     c   r   S
+			 * quad (ambiguous with 4ch)  Fl    Fr   Bl  Br
+			 * 5                          Fl     Fr  Fc  Sl  Sr
+			 * 6                           l     lc  c   r   rc  S
+			 * l:left r:right c:center Fl:front-left Fr:front-right Bl:back-left Br:back-right Lc:left-center Rc:right-center S:surround
+			 * so we only have unambiguous mappings for 2, 3, and 5 channels
+			 */
+			if(
+				options.channel_map_none ||
+				channels == 1 || /* 1 channel: (mono) */
+				channels == 2 || /* 2 channels: left, right */
+				channels == 3 || /* 3 channels: left, right, center */
+				channels == 5    /* 5 channels: front left, front right, center, surround left, surround right */
+			) {
+				/* keep default channel order */
+			}
+			else {
+				flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u for AIFF\n", e->inbasefilename, channels);
+				return false;
+			}
+
+			e->info.bytes_per_wide_sample = channels * (bps / 8);
+
+			/* skip any extra data in the COMM chunk */
+			if(!fskip_ahead(e->fin, skip)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra COMM data\n", e->inbasefilename);
+				return false;
+			}
+
+			got_comm_chunk = true;
+		}
+		else if(!memcmp(chunk_id, "SSND", 4) && !got_ssnd_chunk) { /* sound data chunk */
+			FLAC__uint32 xx;
+			FLAC__uint64 data_bytes;
+			uint32_t offset = 0;
+
+			if(!got_comm_chunk) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: got 'SSND' chunk before 'COMM' chunk\n", e->inbasefilename);
+				return false;
+			}
+
+			/* SSND chunk size */
+			if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+				return false;
+			data_bytes = xx;
+			if(options.ignore_chunk_sizes) {
+				FLAC__ASSERT(!options.sector_align);
+				if(data_bytes) {
+					flac__utils_printf(stderr, 1, "%s: WARNING: 'SSND' chunk has non-zero size, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id);
+					if(e->treat_warnings_as_errors)
+						return false;
+				}
+				data_bytes = (FLAC__uint64)0 - (FLAC__uint64)e->info.bytes_per_wide_sample; /* max out data_bytes; we'll use EOF as signal to stop reading */
+			}
+			else if(data_bytes <= 8) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: 'SSND' chunk has size <= 8\n", e->inbasefilename);
+				return false;
+			}
+			else {
+				data_bytes -= 8; /* discount the offset and block size fields */
+			}
+
+			/* offset */
+			if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+				return false;
+			offset = xx;
+			data_bytes -= offset;
+
+			/* block size */
+			if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+				return false;
+			if(xx && !options.ignore_chunk_sizes)
+				data_bytes -= (xx - (data_bytes % xx));
+			if(options.ignore_chunk_sizes) {
+				if(xx) {
+					flac__utils_printf(stderr, 1, "%s: WARNING: 'SSND' chunk has non-zero blocksize, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id);
+					if(e->treat_warnings_as_errors)
+						return false;
+				}
+			}
+
+			/* skip any SSND offset bytes */
+			if(!fskip_ahead(e->fin, offset)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: skipping offset in SSND chunk\n", e->inbasefilename);
+				return false;
+			}
+
+			e->fmt.iff.data_bytes = data_bytes;
+
+			got_ssnd_chunk = true;
+		}
+		else {
+			FLAC__uint32 xx;
+			if(!options.format_options.iff.foreign_metadata) {
+				flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk '%s' (use --keep-foreign-metadata to keep)\n", e->inbasefilename, chunk_id);
+				if(e->treat_warnings_as_errors)
+					return false;
+			}
+
+			/* chunk size */
+			if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+				return false;
+			else {
+				uint64_t skip = xx + (xx & 1);
+
+				FLAC__ASSERT(skip <= LONG_MAX);
+				if(!fskip_ahead(e->fin, skip)) {
+					flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over chunk\n", e->inbasefilename);
+					return false;
+				}
+			}
+		}
+	}
+
+	if(!got_comm_chunk) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: didn't find COMM chunk\n", e->inbasefilename);
+		return false;
+	}
+	if(!got_ssnd_chunk && sample_frames) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: didn't find SSND chunk\n", e->inbasefilename);
+		return false;
+	}
+
+	e->info.sample_rate = sample_rate;
+	e->info.channels = channels;
+	e->info.bits_per_sample = bps;
+	e->info.shift = shift;
+	e->info.channel_mask = channel_mask;
+
+	return true;
+}
+
+static FLAC__bool get_sample_info_flac(EncoderSession *e)
+{
+	if (!(
+		FLAC__stream_decoder_set_md5_checking(e->fmt.flac.decoder, false) &&
+		FLAC__stream_decoder_set_metadata_respond_all(e->fmt.flac.decoder)
+	)) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: setting up decoder for FLAC input\n", e->inbasefilename);
+		return false;
+	}
+
+	if (e->format == FORMAT_OGGFLAC) {
+		if (FLAC__stream_decoder_init_ogg_stream(e->fmt.flac.decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/e) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for Ogg FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder));
+			return false;
+		}
+	}
+	else if (FLAC__stream_decoder_init_stream(e->fmt.flac.decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/e) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder));
+		return false;
+	}
+
+	if (!FLAC__stream_decoder_process_until_end_of_metadata(e->fmt.flac.decoder) || e->fmt.flac.client_data.fatal_error) {
+		if (e->fmt.flac.client_data.fatal_error)
+			flac__utils_printf(stderr, 1, "%s: ERROR: out of memory or too many metadata blocks while reading metadata in FLAC input\n", e->inbasefilename);
+		else
+			flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder));
+		return false;
+	}
+
+	if (e->fmt.flac.client_data.num_metadata_blocks == 0) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, got no metadata blocks\n", e->inbasefilename);
+		return false;
+	}
+	else if (e->fmt.flac.client_data.metadata_blocks[0]->type != FLAC__METADATA_TYPE_STREAMINFO) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, first metadata block is not STREAMINFO\n", e->inbasefilename);
+		return false;
+	}
+	else if (e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.total_samples == 0) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: FLAC input has STREAMINFO with unknown total samples which is not supported\n", e->inbasefilename);
+		return false;
+	}
+
+	e->info.sample_rate = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.sample_rate;
+	e->info.channels = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.channels;
+	e->info.bits_per_sample = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.bits_per_sample;
+	e->info.shift = 0;
+	e->info.bytes_per_wide_sample = 0;
+	e->info.is_unsigned_samples = false; /* not applicable for FLAC input */
+	e->info.is_big_endian = false; /* not applicable for FLAC input */
+	e->info.channel_mask = 0;
+
+	return true;
+}
+
+/*
+ * public routines
+ */
+int flac__encode_file(FILE *infile, FLAC__off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length, encode_options_t options)
+{
+	EncoderSession encoder_session;
+	size_t channel_map[FLAC__MAX_CHANNELS];
+	int info_align_carry = -1, info_align_zero = -1;
+
+	if(!EncoderSession_construct(&encoder_session, options, infilesize, infile, infilename, outfilename, lookahead, lookahead_length))
+		return 1;
+
+	/* initialize default channel map that preserves channel order */
+	{
+		size_t i;
+		for(i = 0; i < sizeof(channel_map)/sizeof(channel_map[0]); i++)
+			channel_map[i] = i;
+	}
+
+	/* read foreign metadata if requested */
+	if(EncoderSession_format_is_iff(&encoder_session) && options.format_options.iff.foreign_metadata) {
+		const char *error;
+		if(!(
+			options.format == FORMAT_WAVE || options.format == FORMAT_RF64?
+				flac__foreign_metadata_read_from_wave(options.format_options.iff.foreign_metadata, infilename, &error) :
+			options.format == FORMAT_WAVE64?
+				flac__foreign_metadata_read_from_wave64(options.format_options.iff.foreign_metadata, infilename, &error) :
+				flac__foreign_metadata_read_from_aiff(options.format_options.iff.foreign_metadata, infilename, &error)
+		)) {
+			flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", encoder_session.inbasefilename, error);
+			return EncoderSession_finish_error(&encoder_session);
+		}
+	}
+
+	/* initialize encoder session with info about the audio (channels/bps/resolution/endianness/etc) */
+	switch(options.format) {
+		case FORMAT_RAW:
+			if(!get_sample_info_raw(&encoder_session, options))
+				return EncoderSession_finish_error(&encoder_session);
+			break;
+		case FORMAT_WAVE:
+		case FORMAT_WAVE64:
+		case FORMAT_RF64:
+			if(!get_sample_info_wave(&encoder_session, options))
+				return EncoderSession_finish_error(&encoder_session);
+			break;
+		case FORMAT_AIFF:
+		case FORMAT_AIFF_C:
+			if(!get_sample_info_aiff(&encoder_session, options))
+				return EncoderSession_finish_error(&encoder_session);
+			break;
+		case FORMAT_FLAC:
+		case FORMAT_OGGFLAC:
+			/*
+			 * set up FLAC decoder for the input
+			 */
+			if (0 == (encoder_session.fmt.flac.decoder = FLAC__stream_decoder_new())) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: creating decoder for FLAC input\n", encoder_session.inbasefilename);
+				return EncoderSession_finish_error(&encoder_session);
+			}
+			if(!get_sample_info_flac(&encoder_session))
+				return EncoderSession_finish_error(&encoder_session);
+			break;
+		default:
+			FLAC__ASSERT(0);
+			/* double protection */
+			return EncoderSession_finish_error(&encoder_session);
+	}
+
+	/* some more checks */
+	if(encoder_session.info.channels == 0 || encoder_session.info.channels > FLAC__MAX_CHANNELS) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u\n", encoder_session.inbasefilename, encoder_session.info.channels);
+		return EncoderSession_finish_error(&encoder_session);
+	}
+	if(!FLAC__format_sample_rate_is_valid(encoder_session.info.sample_rate)) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: unsupported sample rate %u\n", encoder_session.inbasefilename, encoder_session.info.sample_rate);
+		return EncoderSession_finish_error(&encoder_session);
+	}
+	if(encoder_session.info.bits_per_sample-encoder_session.info.shift < 4 || encoder_session.info.bits_per_sample-encoder_session.info.shift > 24) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: unsupported bits-per-sample %u\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift);
+		return EncoderSession_finish_error(&encoder_session);
+	}
+	if(options.sector_align) {
+		if(encoder_session.info.channels != 2) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: file has %u channels, must be 2 for --sector-align\n", encoder_session.inbasefilename, encoder_session.info.channels);
+			return EncoderSession_finish_error(&encoder_session);
+		}
+		if(encoder_session.info.sample_rate != 44100) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: file's sample rate is %u, must be 44100 for --sector-align\n", encoder_session.inbasefilename, encoder_session.info.sample_rate);
+			return EncoderSession_finish_error(&encoder_session);
+		}
+		if(encoder_session.info.bits_per_sample-encoder_session.info.shift != 16) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: file has %u bits-per-sample, must be 16 for --sector-align\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift);
+			return EncoderSession_finish_error(&encoder_session);
+		}
+	}
+
+	{
+		FLAC__uint64 total_samples_in_input; /* WATCHOUT: may be 0 to mean "unknown" */
+		FLAC__uint64 skip;
+		FLAC__uint64 until; /* a value of 0 mean end-of-stream (i.e. --until=-0) */
+		uint32_t consecutive_eos_count = 0;
+		uint32_t align_remainder = 0;
+
+		switch(options.format) {
+			case FORMAT_RAW:
+				if(infilesize < 0)
+					total_samples_in_input = 0;
+				else
+					total_samples_in_input = (FLAC__uint64)infilesize / encoder_session.info.bytes_per_wide_sample + *options.align_reservoir_samples;
+				break;
+			case FORMAT_WAVE:
+			case FORMAT_WAVE64:
+			case FORMAT_RF64:
+			case FORMAT_AIFF:
+			case FORMAT_AIFF_C:
+				/* truncation in the division removes any padding byte that was counted in encoder_session.fmt.iff.data_bytes */
+				total_samples_in_input = encoder_session.fmt.iff.data_bytes / encoder_session.info.bytes_per_wide_sample + *options.align_reservoir_samples;
+				break;
+			case FORMAT_FLAC:
+			case FORMAT_OGGFLAC:
+				total_samples_in_input = encoder_session.fmt.flac.client_data.metadata_blocks[0]->data.stream_info.total_samples + *options.align_reservoir_samples;
+				break;
+			default:
+				FLAC__ASSERT(0);
+				/* double protection */
+				return EncoderSession_finish_error(&encoder_session);
+		}
+
+		/*
+		 * now that we know the sample rate, canonicalize the
+		 * --skip string to an absolute sample number:
+		 */
+		flac__utils_canonicalize_skip_until_specification(&options.skip_specification, encoder_session.info.sample_rate);
+		FLAC__ASSERT(options.skip_specification.value.samples >= 0);
+		skip = (FLAC__uint64)options.skip_specification.value.samples;
+		FLAC__ASSERT(!options.sector_align || (options.format != FORMAT_FLAC && options.format != FORMAT_OGGFLAC && skip == 0));
+		/* *options.align_reservoir_samples will be 0 unless --sector-align is used */
+		FLAC__ASSERT(options.sector_align || *options.align_reservoir_samples == 0);
+
+		/*
+		 * now that we possibly know the input size, canonicalize the
+		 * --until string to an absolute sample number:
+		 */
+		if(!canonicalize_until_specification(&options.until_specification, encoder_session.inbasefilename, encoder_session.info.sample_rate, skip, total_samples_in_input))
+			return EncoderSession_finish_error(&encoder_session);
+		until = (FLAC__uint64)options.until_specification.value.samples;
+		FLAC__ASSERT(!options.sector_align || until == 0);
+
+		/* adjust encoding parameters based on skip and until values */
+		switch(options.format) {
+			case FORMAT_RAW:
+				infilesize -= (FLAC__off_t)skip * encoder_session.info.bytes_per_wide_sample;
+				encoder_session.total_samples_to_encode = total_samples_in_input - skip;
+				break;
+			case FORMAT_WAVE:
+			case FORMAT_WAVE64:
+			case FORMAT_RF64:
+			case FORMAT_AIFF:
+			case FORMAT_AIFF_C:
+				encoder_session.fmt.iff.data_bytes -= skip * encoder_session.info.bytes_per_wide_sample;
+				if(options.ignore_chunk_sizes) {
+					encoder_session.total_samples_to_encode = 0;
+					FLAC__ASSERT(0 == until);
+				}
+				else {
+					encoder_session.total_samples_to_encode = total_samples_in_input - skip;
+				}
+				break;
+			case FORMAT_FLAC:
+			case FORMAT_OGGFLAC:
+				encoder_session.total_samples_to_encode = total_samples_in_input - skip;
+				break;
+			default:
+				FLAC__ASSERT(0);
+				/* double protection */
+				return EncoderSession_finish_error(&encoder_session);
+		}
+		if(until > 0) {
+			const FLAC__uint64 trim = total_samples_in_input - until;
+			FLAC__ASSERT(total_samples_in_input > 0);
+			FLAC__ASSERT(!options.sector_align);
+			if(options.format == FORMAT_RAW)
+				infilesize -= (FLAC__off_t)trim * encoder_session.info.bytes_per_wide_sample;
+			else if(EncoderSession_format_is_iff(&encoder_session))
+				encoder_session.fmt.iff.data_bytes -= trim * encoder_session.info.bytes_per_wide_sample;
+			encoder_session.total_samples_to_encode -= trim;
+		}
+		if(options.sector_align && (options.format != FORMAT_RAW || infilesize >=0)) { /* for RAW, need to know the filesize */
+			FLAC__ASSERT(skip == 0); /* asserted above too, but lest we forget */
+			align_remainder = (uint32_t)(encoder_session.total_samples_to_encode % 588);
+			if(options.is_last_file)
+				encoder_session.total_samples_to_encode += (588-align_remainder); /* will pad with zeroes */
+			else
+				encoder_session.total_samples_to_encode -= align_remainder; /* will stop short and carry over to next file */
+		}
+		switch(options.format) {
+			case FORMAT_RAW:
+				encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample;
+				break;
+			case FORMAT_WAVE:
+				/* +44 for the size of the WAVE headers; this is just an estimate for the progress indicator and doesn't need to be exact */
+				encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample + 44;
+				break;
+			case FORMAT_WAVE64:
+				/* +44 for the size of the WAVE headers; this is just an estimate for the progress indicator and doesn't need to be exact */
+				encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample + 104;
+				break;
+			case FORMAT_RF64:
+				/* +72 for the size of the RF64 headers; this is just an estimate for the progress indicator and doesn't need to be exact */
+				encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample + 80;
+				break;
+			case FORMAT_AIFF:
+			case FORMAT_AIFF_C:
+				/* +54 for the size of the AIFF headers; this is just an estimate for the progress indicator and doesn't need to be exact */
+				encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample + 54;
+				break;
+			case FORMAT_FLAC:
+			case FORMAT_OGGFLAC:
+				if(infilesize < 0)
+					/* if we don't know, use 0 as hint to progress indicator (which is the only place this is used): */
+					encoder_session.unencoded_size = 0;
+				else if(skip == 0 && until == 0)
+					encoder_session.unencoded_size = (FLAC__uint64)infilesize;
+				else if(total_samples_in_input)
+					encoder_session.unencoded_size = (FLAC__uint64)infilesize * encoder_session.total_samples_to_encode / total_samples_in_input;
+				else
+					encoder_session.unencoded_size = (FLAC__uint64)infilesize;
+				break;
+			default:
+				FLAC__ASSERT(0);
+				/* double protection */
+				return EncoderSession_finish_error(&encoder_session);
+		}
+
+		if(encoder_session.total_samples_to_encode == 0) {
+			encoder_session.unencoded_size = 0;
+			flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n");
+		}
+
+		if(options.format == FORMAT_FLAC || options.format == FORMAT_OGGFLAC)
+			encoder_session.fmt.flac.client_data.samples_left_to_process = encoder_session.total_samples_to_encode;
+
+		stats_new_file();
+		/* init the encoder */
+		if(!EncoderSession_init_encoder(&encoder_session, options))
+			return EncoderSession_finish_error(&encoder_session);
+
+		/* skip over any samples as requested */
+		if(skip > 0) {
+			switch(options.format) {
+				case FORMAT_RAW:
+					{
+						uint32_t skip_bytes = encoder_session.info.bytes_per_wide_sample * (uint32_t)skip;
+						if(skip_bytes > lookahead_length) {
+							skip_bytes -= lookahead_length;
+							lookahead_length = 0;
+							if(!fskip_ahead(encoder_session.fin, skip_bytes)) {
+								flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename);
+								return EncoderSession_finish_error(&encoder_session);
+							}
+						}
+						else {
+							lookahead += skip_bytes;
+							lookahead_length -= skip_bytes;
+						}
+					}
+					break;
+				case FORMAT_WAVE:
+				case FORMAT_WAVE64:
+				case FORMAT_RF64:
+				case FORMAT_AIFF:
+				case FORMAT_AIFF_C:
+					if(!fskip_ahead(encoder_session.fin, skip * encoder_session.info.bytes_per_wide_sample)) {
+						flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename);
+						return EncoderSession_finish_error(&encoder_session);
+					}
+					break;
+				case FORMAT_FLAC:
+				case FORMAT_OGGFLAC:
+					/*
+					 * have to wait until the FLAC encoder is set up for writing
+					 * before any seeking in the input FLAC file, because the seek
+					 * itself will usually call the decoder's write callback, and
+					 * our decoder's write callback passes samples to our FLAC
+					 * encoder
+					 */
+					if(!FLAC__stream_decoder_seek_absolute(encoder_session.fmt.flac.decoder, skip)) {
+						flac__utils_printf(stderr, 1, "%s: ERROR while skipping samples, FLAC decoder state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(encoder_session.fmt.flac.decoder));
+						return EncoderSession_finish_error(&encoder_session);
+					}
+					break;
+				default:
+					FLAC__ASSERT(0);
+					/* double protection */
+					return EncoderSession_finish_error(&encoder_session);
+			}
+		}
+
+		/*
+		 * first do any samples in the reservoir
+		 */
+		if(options.sector_align && *options.align_reservoir_samples > 0) {
+			FLAC__ASSERT(options.format != FORMAT_FLAC && options.format != FORMAT_OGGFLAC); /* check again */
+			if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)options.align_reservoir, *options.align_reservoir_samples)) {
+				print_error_with_state(&encoder_session, "ERROR during encoding");
+				return EncoderSession_finish_error(&encoder_session);
+			}
+		}
+
+		/*
+		 * decrement infilesize or the data_bytes counter if we need to align the file
+		 */
+		if(options.sector_align) {
+			if(options.is_last_file) {
+				*options.align_reservoir_samples = 0;
+			}
+			else {
+				*options.align_reservoir_samples = align_remainder;
+				if(options.format == FORMAT_RAW) {
+					FLAC__ASSERT(infilesize >= 0);
+					infilesize -= (FLAC__off_t)((*options.align_reservoir_samples) * encoder_session.info.bytes_per_wide_sample);
+					FLAC__ASSERT(infilesize >= 0);
+				}
+				else if(EncoderSession_format_is_iff(&encoder_session))
+					encoder_session.fmt.iff.data_bytes -= (*options.align_reservoir_samples) * encoder_session.info.bytes_per_wide_sample;
+			}
+		}
+
+		/*
+		 * now do samples from the file
+		 */
+		switch(options.format) {
+			case FORMAT_RAW:
+				if(infilesize < 0) {
+					size_t bytes_read;
+					while(!feof(infile)) {
+						if(lookahead_length > 0) {
+							FLAC__ASSERT(lookahead_length < CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample);
+							memcpy(ubuffer.u8, lookahead, lookahead_length);
+							bytes_read = fread(ubuffer.u8+lookahead_length, sizeof(uint8_t), CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample - lookahead_length, infile) + lookahead_length;
+							if(ferror(infile)) {
+								flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+								return EncoderSession_finish_error(&encoder_session);
+							}
+							lookahead_length = 0;
+						}
+						else
+							bytes_read = fread(ubuffer.u8, sizeof(uint8_t), CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample, infile);
+
+						if(bytes_read == 0) {
+							if(ferror(infile)) {
+								flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+								return EncoderSession_finish_error(&encoder_session);
+							}
+						}
+						else if(bytes_read % encoder_session.info.bytes_per_wide_sample != 0) {
+							flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename);
+							return EncoderSession_finish_error(&encoder_session);
+						}
+						else {
+							uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample;
+							if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.shift, channel_map))
+								return EncoderSession_finish_error(&encoder_session);
+
+							if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+								print_error_with_state(&encoder_session, "ERROR during encoding");
+								return EncoderSession_finish_error(&encoder_session);
+							}
+						}
+					}
+				}
+				else {
+					size_t bytes_read;
+					const FLAC__uint64 max_input_bytes = infilesize;
+					FLAC__uint64 total_input_bytes_read = 0;
+					while(total_input_bytes_read < max_input_bytes) {
+						{
+							size_t wanted = (CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample);
+							wanted = (size_t) min((FLAC__uint64)wanted, max_input_bytes - total_input_bytes_read);
+
+							if(lookahead_length > 0) {
+								FLAC__ASSERT(lookahead_length <= wanted);
+								memcpy(ubuffer.u8, lookahead, lookahead_length);
+								wanted -= lookahead_length;
+								bytes_read = lookahead_length;
+								if(wanted > 0) {
+									bytes_read += fread(ubuffer.u8+lookahead_length, sizeof(uint8_t), wanted, infile);
+									if(ferror(infile)) {
+										flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+										return EncoderSession_finish_error(&encoder_session);
+									}
+								}
+								lookahead_length = 0;
+							}
+							else
+								bytes_read = fread(ubuffer.u8, sizeof(uint8_t), wanted, infile);
+						}
+
+						if(bytes_read == 0) {
+							if(ferror(infile)) {
+								flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+								return EncoderSession_finish_error(&encoder_session);
+							}
+							else if(feof(infile)) {
+								flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %" PRIu64 " samples, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.total_samples_to_encode, encoder_session.samples_written);
+								if(encoder_session.treat_warnings_as_errors)
+									return EncoderSession_finish_error(&encoder_session);
+								total_input_bytes_read = max_input_bytes;
+							}
+						}
+						else {
+							if(bytes_read % encoder_session.info.bytes_per_wide_sample != 0) {
+								flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename);
+								return EncoderSession_finish_error(&encoder_session);
+							}
+							else {
+								uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample;
+								if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.shift, channel_map))
+									return EncoderSession_finish_error(&encoder_session);
+
+								if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+									print_error_with_state(&encoder_session, "ERROR during encoding");
+									return EncoderSession_finish_error(&encoder_session);
+								}
+								total_input_bytes_read += bytes_read;
+							}
+						}
+					}
+				}
+				break;
+			case FORMAT_WAVE:
+			case FORMAT_WAVE64:
+			case FORMAT_RF64:
+			case FORMAT_AIFF:
+			case FORMAT_AIFF_C:
+				while(encoder_session.fmt.iff.data_bytes > 0) {
+					const size_t bytes_to_read =
+						(size_t) min (sizeof (ubuffer.u8),
+							min (encoder_session.fmt.iff.data_bytes,
+								CHUNK_OF_SAMPLES * (uint64_t) encoder_session.info.bytes_per_wide_sample));
+					size_t bytes_read = fread(ubuffer.u8, sizeof(uint8_t), bytes_to_read, infile);
+					if(bytes_read == 0) {
+						if(ferror(infile)) {
+							flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+							return EncoderSession_finish_error(&encoder_session);
+						}
+						else if(feof(infile)) {
+							if(options.ignore_chunk_sizes) {
+								flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.samples_written);
+							}
+							else {
+								flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %" PRIu64 " samples, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.total_samples_to_encode, encoder_session.samples_written);
+								if(encoder_session.treat_warnings_as_errors)
+									return EncoderSession_finish_error(&encoder_session);
+							}
+							encoder_session.fmt.iff.data_bytes = 0;
+						}
+					}
+					else {
+						if(bytes_read % encoder_session.info.bytes_per_wide_sample != 0) {
+							flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename);
+							return EncoderSession_finish_error(&encoder_session);
+						}
+						else {
+							uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample;
+							if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.shift, channel_map))
+								return EncoderSession_finish_error(&encoder_session);
+
+							if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+								print_error_with_state(&encoder_session, "ERROR during encoding");
+								return EncoderSession_finish_error(&encoder_session);
+							}
+							encoder_session.fmt.iff.data_bytes -= bytes_read;
+						}
+					}
+				}
+				break;
+			case FORMAT_FLAC:
+			case FORMAT_OGGFLAC:
+				consecutive_eos_count = 0;
+				while(!encoder_session.fmt.flac.client_data.fatal_error && encoder_session.fmt.flac.client_data.samples_left_to_process > 0) {
+					FLAC__StreamDecoderState decoder_state;
+					/* We can also hit the end of stream without samples_left_to_process
+					 * going to 0 if there are errors and continue_through_decode_errors
+					 * is on, so we want to break in that case too:
+					 */
+					decoder_state = FLAC__stream_decoder_get_state(encoder_session.fmt.flac.decoder);
+					if(encoder_session.continue_through_decode_errors && decoder_state == FLAC__STREAM_DECODER_END_OF_STREAM)
+						break;
+
+					consecutive_eos_count = decoder_state == FLAC__STREAM_DECODER_END_OF_STREAM ? consecutive_eos_count + 1 : 0;
+
+					/* Exit loop if we get two or more consecutive FLAC__STREAM_DECODER_END_OF_STREAM events. */
+					if(consecutive_eos_count >= 2) {
+						flac__utils_printf(stderr, 1, "%s: ERROR: %d consecutive FLAC__STREAM_DECODER_END_OF_STREAM events.\n", encoder_session.inbasefilename, consecutive_eos_count);
+						break;
+					}
+
+					if(!FLAC__stream_decoder_process_single(encoder_session.fmt.flac.decoder)) {
+						flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(encoder_session.fmt.flac.decoder));
+						return EncoderSession_finish_error(&encoder_session);
+					}
+				}
+				if(encoder_session.fmt.flac.client_data.fatal_error) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(encoder_session.fmt.flac.decoder));
+					return EncoderSession_finish_error(&encoder_session);
+				}
+				break;
+			default:
+				FLAC__ASSERT(0);
+				/* double protection */
+				return EncoderSession_finish_error(&encoder_session);
+		}
+
+		/*
+		 * now read unaligned samples into reservoir or pad with zeroes if necessary
+		 */
+		if(options.sector_align) {
+			if(options.is_last_file) {
+				uint32_t wide_samples = 588 - align_remainder;
+				if(wide_samples < 588) {
+					uint32_t channel;
+
+					info_align_zero = wide_samples;
+					for(channel = 0; channel < encoder_session.info.channels; channel++)
+						memset(input_[channel], 0, sizeof(input_[0][0]) * wide_samples);
+
+					if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+						print_error_with_state(&encoder_session, "ERROR during encoding");
+						return EncoderSession_finish_error(&encoder_session);
+					}
+				}
+			}
+			else {
+				if(*options.align_reservoir_samples > 0) {
+					size_t bytes_read;
+					FLAC__ASSERT(CHUNK_OF_SAMPLES >= 588);
+					bytes_read = fread(ubuffer.u8, sizeof(uint8_t), (*options.align_reservoir_samples) * encoder_session.info.bytes_per_wide_sample, infile);
+					if(bytes_read == 0 && ferror(infile)) {
+						flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+						return EncoderSession_finish_error(&encoder_session);
+					}
+					else if(bytes_read != (*options.align_reservoir_samples) * encoder_session.info.bytes_per_wide_sample) {
+						flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; read %" PRIu64 " bytes; expected %" PRIu64 " samples, got %" PRIu64 " samples\n", encoder_session.inbasefilename, bytes_read, encoder_session.total_samples_to_encode, encoder_session.samples_written);
+						if(encoder_session.treat_warnings_as_errors)
+							return EncoderSession_finish_error(&encoder_session);
+					}
+					else {
+						info_align_carry = *options.align_reservoir_samples;
+						if(!format_input(options.align_reservoir, *options.align_reservoir_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.shift, channel_map))
+							return EncoderSession_finish_error(&encoder_session);
+					}
+				}
+			}
+		}
+	}
+
+	return EncoderSession_finish_ok(
+		&encoder_session,
+		info_align_carry,
+		info_align_zero,
+		EncoderSession_format_is_iff(&encoder_session)? options.format_options.iff.foreign_metadata : 0,
+		options.error_on_compression_fail
+	);
+}
+
+FLAC__bool EncoderSession_construct(EncoderSession *e, encode_options_t options, FLAC__off_t infilesize, FILE *infile, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length)
+{
+	uint32_t i;
+	FLAC__uint32 test = 1;
+
+	/*
+	 * initialize globals
+	 */
+
+	is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+		input_[i] = &(in_[i][0]);
+
+
+	/*
+	 * initialize instance
+	 */
+
+#if FLAC__HAS_OGG
+	e->use_ogg = options.use_ogg;
+#endif
+	e->verify = options.verify;
+	e->treat_warnings_as_errors = options.treat_warnings_as_errors;
+	e->continue_through_decode_errors = options.continue_through_decode_errors;
+
+	e->is_stdout = (0 == strcmp(outfilename, "-"));
+	e->outputfile_opened = false;
+
+	e->inbasefilename = grabbag__file_get_basename(infilename);
+	e->infilename = infilename;
+	e->outfilename = outfilename;
+
+	e->total_samples_to_encode = 0;
+	e->unencoded_size = 0;
+	e->bytes_written = 0;
+	e->samples_written = 0;
+	e->stats_frames_interval = 0;
+	e->old_frames_written = 0;
+
+	memset(&e->info, 0, sizeof(e->info));
+
+	e->format = options.format;
+
+	switch(options.format) {
+		case FORMAT_RAW:
+			break;
+		case FORMAT_WAVE:
+		case FORMAT_WAVE64:
+		case FORMAT_RF64:
+		case FORMAT_AIFF:
+		case FORMAT_AIFF_C:
+			e->fmt.iff.data_bytes = 0;
+			break;
+		case FORMAT_FLAC:
+		case FORMAT_OGGFLAC:
+			e->fmt.flac.decoder = 0;
+			e->fmt.flac.client_data.filesize = infilesize;
+			e->fmt.flac.client_data.lookahead = lookahead;
+			e->fmt.flac.client_data.lookahead_length = lookahead_length;
+			e->fmt.flac.client_data.num_metadata_blocks = 0;
+			e->fmt.flac.client_data.samples_left_to_process = 0;
+			e->fmt.flac.client_data.fatal_error = false;
+			break;
+		default:
+			FLAC__ASSERT(0);
+			/* double protection */
+			return false;
+	}
+
+	e->encoder = 0;
+
+	e->fin = infile;
+	e->seek_table_template = 0;
+
+	if(0 == (e->seek_table_template = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE))) {
+		flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for seek table\n", e->inbasefilename);
+		return false;
+	}
+
+	e->encoder = FLAC__stream_encoder_new();
+	if(0 == e->encoder) {
+		flac__utils_printf(stderr, 1, "%s: ERROR creating the encoder instance\n", e->inbasefilename);
+		EncoderSession_destroy(e);
+		return false;
+	}
+
+	return true;
+}
+
+void EncoderSession_destroy(EncoderSession *e)
+{
+	if(e->format == FORMAT_FLAC || e->format == FORMAT_OGGFLAC) {
+		size_t i;
+		if(e->fmt.flac.decoder)
+			FLAC__stream_decoder_delete(e->fmt.flac.decoder);
+		e->fmt.flac.decoder = 0;
+		for(i = 0; i < e->fmt.flac.client_data.num_metadata_blocks; i++)
+			FLAC__metadata_object_delete(e->fmt.flac.client_data.metadata_blocks[i]);
+		e->fmt.flac.client_data.num_metadata_blocks = 0;
+	}
+
+	if(e->fin != stdin)
+		fclose(e->fin);
+
+	if(0 != e->encoder) {
+		FLAC__stream_encoder_delete(e->encoder);
+		e->encoder = 0;
+	}
+
+	if(0 != e->seek_table_template) {
+		FLAC__metadata_object_delete(e->seek_table_template);
+		e->seek_table_template = 0;
+	}
+}
+
+int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int info_align_zero, foreign_metadata_t *foreign_metadata, FLAC__bool error_on_compression_fail)
+{
+	FLAC__StreamEncoderState fse_state = FLAC__STREAM_ENCODER_OK;
+	int ret = 0;
+	FLAC__bool verify_error = false;
+
+	if(e->encoder) {
+		fse_state = FLAC__stream_encoder_get_state(e->encoder);
+		ret = FLAC__stream_encoder_finish(e->encoder)? 0 : 1;
+		verify_error =
+			fse_state == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA ||
+			FLAC__stream_encoder_get_state(e->encoder) == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA
+		;
+	}
+	/* all errors except verify errors should interrupt the stats */
+	if(ret && !verify_error)
+		print_error_with_state(e, "ERROR during encoding");
+	else if(e->total_samples_to_encode > 0) {
+		print_stats(e);
+		flac__utils_printf(stderr, 2, "\n");
+	}
+
+	if(verify_error) {
+		print_verify_error(e);
+		ret = 1;
+	}
+	else {
+		if(info_align_carry >= 0) {
+			flac__utils_printf(stderr, 1, "%s: INFO: sector alignment causing %d samples to be carried over\n", e->inbasefilename, info_align_carry);
+		}
+		if(info_align_zero >= 0) {
+			flac__utils_printf(stderr, 1, "%s: INFO: sector alignment causing %d zero samples to be appended\n", e->inbasefilename, info_align_zero);
+		}
+	}
+
+	/*@@@@@@ should this go here or somewhere else? */
+	if(ret == 0 && foreign_metadata) {
+		const char *error;
+		if(!flac__foreign_metadata_write_to_flac(foreign_metadata, e->infilename, e->outfilename, &error)) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: updating foreign metadata in FLAC file: %s\n", e->inbasefilename, error);
+			ret = 1;
+		}
+	}
+
+	if (e->compression_ratio >= 1.0 && error_on_compression_fail) {
+		flac__utils_printf(stderr, 1,
+			"FAILURE: Compression failed (ratio %0.3f, should be < 1.0).\n"
+			"This happens for some files for one or more of the following reasons:\n"
+			" * Recompressing an existing FLAC from a higher to a lower compression setting.\n"
+			" * Insufficient input data  (e.g. very short files, < 10000 frames).\n"
+			" * The audio data is not compressible (e.g. a full range white noise signal).\n"
+			, e->compression_ratio);
+		ret = 1;
+	}
+
+	EncoderSession_destroy(e);
+
+	return ret;
+}
+
+int EncoderSession_finish_error(EncoderSession *e)
+{
+	FLAC__ASSERT(e->encoder);
+
+	if(e->total_samples_to_encode > 0)
+		flac__utils_printf(stderr, 2, "\n");
+
+	if(FLAC__stream_encoder_get_state(e->encoder) == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA)
+		print_verify_error(e);
+	else if(e->outputfile_opened)
+		/* only want to delete the file if we opened it; otherwise it could be an existing file and our overwrite failed */
+		flac_unlink(e->outfilename);
+
+	EncoderSession_destroy(e);
+
+	return 1;
+}
+
+typedef struct {
+	uint32_t num_metadata;
+	FLAC__bool *needs_delete;
+	FLAC__StreamMetadata **metadata;
+	FLAC__StreamMetadata *cuesheet; /* always needs to be deleted */
+} static_metadata_t;
+
+static void static_metadata_init(static_metadata_t *m)
+{
+	m->num_metadata = 0;
+	m->needs_delete = 0;
+	m->metadata = 0;
+	m->cuesheet = 0;
+}
+
+static void static_metadata_clear(static_metadata_t *m)
+{
+	uint32_t i;
+	for(i = 0; i < m->num_metadata; i++)
+		if(m->needs_delete[i])
+			FLAC__metadata_object_delete(m->metadata[i]);
+	if(m->metadata)
+		free(m->metadata);
+	if(m->needs_delete)
+		free(m->needs_delete);
+	if(m->cuesheet)
+		FLAC__metadata_object_delete(m->cuesheet);
+	static_metadata_init(m);
+}
+
+static FLAC__bool static_metadata_append(static_metadata_t *m, FLAC__StreamMetadata *d, FLAC__bool needs_delete)
+{
+	void *x;
+	if(0 == (x = safe_realloc_muladd2_(m->metadata, sizeof(*m->metadata), /*times (*/m->num_metadata, /*+*/1/*)*/)))
+		return false;
+	m->metadata = (FLAC__StreamMetadata**)x;
+	if(0 == (x = safe_realloc_muladd2_(m->needs_delete, sizeof(*m->needs_delete), /*times (*/m->num_metadata, /*+*/1/*)*/)))
+		return false;
+	m->needs_delete = (FLAC__bool*)x;
+	m->metadata[m->num_metadata] = d;
+	m->needs_delete[m->num_metadata] = needs_delete;
+	m->num_metadata++;
+	return true;
+}
+
+FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options)
+{
+	const uint32_t channels = e->info.channels;
+	const uint32_t bps = e->info.bits_per_sample - e->info.shift;
+	const uint32_t sample_rate = e->info.sample_rate;
+	FLACDecoderData *flac_decoder_data = (e->format == FORMAT_FLAC || e->format == FORMAT_OGGFLAC)? &e->fmt.flac.client_data : 0;
+	FLAC__StreamMetadata padding;
+	FLAC__StreamMetadata **metadata = 0;
+	static_metadata_t static_metadata;
+	uint32_t num_metadata = 0, ic;
+	FLAC__StreamEncoderInitStatus init_status;
+	const FLAC__bool is_cdda = (channels == 1 || channels == 2) && (bps == 16) && (sample_rate == 44100);
+	char apodizations[2000];
+
+	FLAC__ASSERT(sizeof(options.pictures)/sizeof(options.pictures[0]) <= 64);
+
+	static_metadata_init(&static_metadata);
+
+	e->replay_gain = options.replay_gain;
+
+	apodizations[0] = '\0';
+
+	if(e->replay_gain) {
+		if(channels != 1 && channels != 2) {
+			flac__utils_printf(stderr, 1, "%s: ERROR, number of channels (%u) must be 1 or 2 for --replay-gain\n", e->inbasefilename, channels);
+			return false;
+		}
+		if(!grabbag__replaygain_is_valid_sample_frequency(sample_rate)) {
+			flac__utils_printf(stderr, 1, "%s: ERROR, invalid sample rate (%u) for --replay-gain\n", e->inbasefilename, sample_rate);
+			return false;
+		}
+		if(options.is_first_file) {
+			if(!grabbag__replaygain_init(sample_rate)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR initializing ReplayGain stage\n", e->inbasefilename);
+				return false;
+			}
+		}
+	}
+
+	if(!parse_cuesheet(&static_metadata.cuesheet, options.cuesheet_filename, e->inbasefilename, sample_rate, is_cdda, e->total_samples_to_encode, e->treat_warnings_as_errors))
+		return false;
+
+	if(!convert_to_seek_table_template(options.requested_seek_points, options.num_requested_seek_points, options.cued_seekpoints? static_metadata.cuesheet : 0, e)) {
+		flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for seek table\n", e->inbasefilename);
+		static_metadata_clear(&static_metadata);
+		return false;
+	}
+
+	/* build metadata */
+	if(flac_decoder_data) {
+		/*
+		 * we're encoding from FLAC so we will use the FLAC file's
+		 * metadata as the basis for the encoded file
+		 */
+		{
+			uint32_t i;
+			/*
+			 * first handle pictures: simple append any --pictures
+			 * specified.
+			 */
+			for(i = 0; i < options.num_pictures; i++) {
+				FLAC__StreamMetadata *pic = FLAC__metadata_object_clone(options.pictures[i]);
+				if(0 == pic) {
+					flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for PICTURE block\n", e->inbasefilename);
+					static_metadata_clear(&static_metadata);
+					return false;
+				}
+				flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks++] = pic;
+			}
+		}
+		{
+			/*
+			 * next handle vorbis comment: if any tags were specified
+			 * or there is no existing vorbis comment, we create a
+			 * new vorbis comment (discarding any existing one); else
+			 * we keep the existing one.  also need to make sure to
+			 * propagate any channel mask tag.
+			 */
+			/* @@@ change to append -T values from options.vorbis_comment if input has VC already? */
+			size_t i, j;
+			FLAC__bool vc_found = false;
+			for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) {
+				if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+					vc_found = true;
+				if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && options.vorbis_comment->data.vorbis_comment.num_comments > 0) {
+					(void) flac__utils_get_channel_mask_tag(flac_decoder_data->metadata_blocks[i], &e->info.channel_mask);
+					flac__utils_printf(stderr, 1, "%s: WARNING, replacing tags from input FLAC file with those given on the command-line\n", e->inbasefilename);
+					if(e->treat_warnings_as_errors) {
+						static_metadata_clear(&static_metadata);
+						return false;
+					}
+					FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]);
+					flac_decoder_data->metadata_blocks[i] = 0;
+				}
+				else
+					flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i];
+			}
+			flac_decoder_data->num_metadata_blocks = j;
+			if((!vc_found || options.vorbis_comment->data.vorbis_comment.num_comments > 0) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) {
+				/* prepend ours */
+				FLAC__StreamMetadata *vc = FLAC__metadata_object_clone(options.vorbis_comment);
+				if(0 == vc || (e->info.channel_mask && !flac__utils_set_channel_mask_tag(vc, e->info.channel_mask))) {
+					flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for VORBIS_COMMENT block\n", e->inbasefilename);
+					static_metadata_clear(&static_metadata);
+					return false;
+				}
+				for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--)
+					flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1];
+				flac_decoder_data->metadata_blocks[1] = vc;
+				flac_decoder_data->num_metadata_blocks++;
+			}
+		}
+		{
+			/*
+			 * next handle cuesheet: if --cuesheet was specified, use
+			 * it; else if file has existing CUESHEET and cuesheet's
+			 * lead-out offset is correct, keep it; else no CUESHEET
+			 */
+			size_t i, j;
+			for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) {
+				FLAC__bool existing_cuesheet_is_bad = false;
+				/* check if existing cuesheet matches the input audio */
+				if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_CUESHEET && 0 == static_metadata.cuesheet) {
+					const FLAC__StreamMetadata_CueSheet *cs = &flac_decoder_data->metadata_blocks[i]->data.cue_sheet;
+					if(e->total_samples_to_encode == 0) {
+						flac__utils_printf(stderr, 1, "%s: WARNING, cuesheet in input FLAC file cannot be kept if input size is not known, dropping it...\n", e->inbasefilename);
+						if(e->treat_warnings_as_errors) {
+							static_metadata_clear(&static_metadata);
+							return false;
+						}
+						existing_cuesheet_is_bad = true;
+					}
+					else if(cs->num_tracks > 0 && e->total_samples_to_encode != cs->tracks[cs->num_tracks-1].offset) {
+						flac__utils_printf(stderr, 1, "%s: WARNING, lead-out offset of cuesheet in input FLAC file does not match input length, dropping existing cuesheet...\n", e->inbasefilename);
+						if(e->treat_warnings_as_errors) {
+							static_metadata_clear(&static_metadata);
+							return false;
+						}
+						existing_cuesheet_is_bad = true;
+					}
+				}
+				if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_CUESHEET && (existing_cuesheet_is_bad || 0 != static_metadata.cuesheet)) {
+					if(0 != static_metadata.cuesheet) {
+						flac__utils_printf(stderr, 1, "%s: WARNING, replacing cuesheet in input FLAC file with the one given on the command-line\n", e->inbasefilename);
+						if(e->treat_warnings_as_errors) {
+							static_metadata_clear(&static_metadata);
+							return false;
+						}
+					}
+					FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]);
+					flac_decoder_data->metadata_blocks[i] = 0;
+				}
+				else
+					flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i];
+			}
+			flac_decoder_data->num_metadata_blocks = j;
+			if(0 != static_metadata.cuesheet && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) {
+				/* prepend ours */
+				FLAC__StreamMetadata *cs = FLAC__metadata_object_clone(static_metadata.cuesheet);
+				if(0 == cs) {
+					flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for CUESHEET block\n", e->inbasefilename);
+					static_metadata_clear(&static_metadata);
+					return false;
+				}
+				for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--)
+					flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1];
+				flac_decoder_data->metadata_blocks[1] = cs;
+				flac_decoder_data->num_metadata_blocks++;
+			}
+		}
+		{
+			/*
+			 * next handle seektable: if -S- was specified, no
+			 * SEEKTABLE; else if -S was specified, use it/them;
+			 * else if file has existing SEEKTABLE and input size is
+			 * preserved (no --skip/--until/etc specified), keep it;
+			 * else use default seektable options
+			 *
+			 * note: meanings of num_requested_seek_points:
+			 *  -1 : no -S option given, default to some value
+			 *   0 : -S- given (no seektable)
+			 *  >0 : one or more -S options given
+			 */
+			size_t i, j;
+			FLAC__bool existing_seektable = false;
+			for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) {
+				if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_SEEKTABLE)
+					existing_seektable = true;
+				if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_SEEKTABLE && (e->total_samples_to_encode != flac_decoder_data->metadata_blocks[0]->data.stream_info.total_samples || options.num_requested_seek_points >= 0)) {
+					if(options.num_requested_seek_points > 0) {
+						flac__utils_printf(stderr, 1, "%s: WARNING, replacing seektable in input FLAC file with the one given on the command-line\n", e->inbasefilename);
+						if(e->treat_warnings_as_errors) {
+							static_metadata_clear(&static_metadata);
+							return false;
+						}
+					}
+					else if(options.num_requested_seek_points == 0)
+						; /* no warning, silently delete existing SEEKTABLE since user specified --no-seektable (-S-) */
+					else {
+						flac__utils_printf(stderr, 1, "%s: WARNING, can't use existing seektable in input FLAC since the input size is changing or unknown, dropping existing SEEKTABLE block...\n", e->inbasefilename);
+						if(e->treat_warnings_as_errors) {
+							static_metadata_clear(&static_metadata);
+							return false;
+						}
+					}
+					FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]);
+					flac_decoder_data->metadata_blocks[i] = 0;
+					existing_seektable = false;
+				}
+				else
+					flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i];
+			}
+			flac_decoder_data->num_metadata_blocks = j;
+			if((options.num_requested_seek_points > 0 || (options.num_requested_seek_points < 0 && !existing_seektable)) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) {
+				/* prepend ours */
+				FLAC__StreamMetadata *st = FLAC__metadata_object_clone(e->seek_table_template);
+				if(0 == st) {
+					flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for SEEKTABLE block\n", e->inbasefilename);
+					static_metadata_clear(&static_metadata);
+					return false;
+				}
+				for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--)
+					flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1];
+				flac_decoder_data->metadata_blocks[1] = st;
+				flac_decoder_data->num_metadata_blocks++;
+			}
+		}
+		{
+			/*
+			 * finally handle padding: if --no-padding was specified,
+			 * then delete all padding; else if -P was specified,
+			 * use that instead of existing padding (if any); else
+			 * if existing file has padding, move all existing
+			 * padding blocks to one padding block at the end; else
+			 * use default padding.
+			 */
+			int p = -1;
+			size_t i, j;
+			for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) {
+				if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_PADDING) {
+					if(p < 0)
+						p = 0;
+					p += flac_decoder_data->metadata_blocks[i]->length;
+					FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]);
+					flac_decoder_data->metadata_blocks[i] = 0;
+				}
+				else
+					flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i];
+			}
+			flac_decoder_data->num_metadata_blocks = j;
+			if(options.padding > 0)
+				p = options.padding;
+			if(p < 0)
+				p = e->total_samples_to_encode / sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8;
+			if(p > 0)
+				p += (e->replay_gain ? GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED : 0);
+			p = min(p, (int)((1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1));
+			if(options.padding != 0) {
+				if(p > 0 && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) {
+					flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+					if(0 == flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]) {
+						flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for PADDING block\n", e->inbasefilename);
+						static_metadata_clear(&static_metadata);
+						return false;
+					}
+					flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]->is_last = false; /* the encoder will set this for us */
+					flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]->length = p;
+					flac_decoder_data->num_metadata_blocks++;
+				}
+			}
+		}
+		metadata = &flac_decoder_data->metadata_blocks[1]; /* don't include STREAMINFO */
+		num_metadata = flac_decoder_data->num_metadata_blocks - 1;
+	}
+	else {
+		/*
+		 * we're not encoding from FLAC so we will build the metadata
+		 * from scratch
+		 */
+		const foreign_metadata_t *foreign_metadata = EncoderSession_format_is_iff(e)? options.format_options.iff.foreign_metadata : 0;
+		uint32_t i;
+
+		if(e->seek_table_template->data.seek_table.num_points > 0) {
+			e->seek_table_template->is_last = false; /* the encoder will set this for us */
+			static_metadata_append(&static_metadata, e->seek_table_template, /*needs_delete=*/false);
+		}
+		if(0 != static_metadata.cuesheet)
+			static_metadata_append(&static_metadata, static_metadata.cuesheet, /*needs_delete=*/false);
+		if(e->info.channel_mask) {
+			if(!flac__utils_set_channel_mask_tag(options.vorbis_comment, e->info.channel_mask)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR adding channel mask tag\n", e->inbasefilename);
+				static_metadata_clear(&static_metadata);
+				return false;
+			}
+		}
+		static_metadata_append(&static_metadata, options.vorbis_comment, /*needs_delete=*/false);
+		for(i = 0; i < options.num_pictures; i++)
+			static_metadata_append(&static_metadata, options.pictures[i], /*needs_delete=*/false);
+		if(foreign_metadata) {
+			for(i = 0; i < foreign_metadata->num_blocks; i++) {
+				FLAC__StreamMetadata *p = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+				if(!p) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: out of memory\n", e->inbasefilename);
+					static_metadata_clear(&static_metadata);
+					return false;
+				}
+				static_metadata_append(&static_metadata, p, /*needs_delete=*/true);
+				static_metadata.metadata[static_metadata.num_metadata-1]->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8 + foreign_metadata->blocks[i].size;
+			}
+		}
+		if(options.padding != 0) {
+			padding.is_last = false; /* the encoder will set this for us */
+			padding.type = FLAC__METADATA_TYPE_PADDING;
+			padding.length = (uint32_t)(options.padding>0? options.padding : (e->total_samples_to_encode / sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8)) + (e->replay_gain ? GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED : 0);
+			padding.length = min(padding.length, (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1);
+			static_metadata_append(&static_metadata, &padding, /*needs_delete=*/false);
+		}
+		metadata = static_metadata.metadata;
+		num_metadata = static_metadata.num_metadata;
+	}
+
+	/* check for a few things that have not already been checked.  the
+	 * FLAC__stream_encoder_init*() will check it but only return
+	 * FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA so we check some
+	 * up front to give a better error message.
+	 */
+	if(!verify_metadata(e, metadata, num_metadata)) {
+		static_metadata_clear(&static_metadata);
+		return false;
+	}
+
+	FLAC__stream_encoder_set_verify(e->encoder, options.verify);
+	FLAC__stream_encoder_set_streamable_subset(e->encoder, !options.lax);
+	FLAC__stream_encoder_set_channels(e->encoder, channels);
+	FLAC__stream_encoder_set_bits_per_sample(e->encoder, bps);
+	FLAC__stream_encoder_set_sample_rate(e->encoder, sample_rate);
+	for(ic = 0; ic < options.num_compression_settings; ic++) {
+		switch(options.compression_settings[ic].type) {
+			case CST_BLOCKSIZE:
+				FLAC__stream_encoder_set_blocksize(e->encoder, options.compression_settings[ic].value.t_unsigned);
+				break;
+			case CST_COMPRESSION_LEVEL:
+				FLAC__stream_encoder_set_compression_level(e->encoder, options.compression_settings[ic].value.t_unsigned);
+				apodizations[0] = '\0';
+				break;
+			case CST_DO_MID_SIDE:
+				FLAC__stream_encoder_set_do_mid_side_stereo(e->encoder, options.compression_settings[ic].value.t_bool);
+				break;
+			case CST_LOOSE_MID_SIDE:
+				FLAC__stream_encoder_set_loose_mid_side_stereo(e->encoder, options.compression_settings[ic].value.t_bool);
+				break;
+			case CST_APODIZATION:
+				if(strlen(apodizations)+strlen(options.compression_settings[ic].value.t_string)+2 >= sizeof(apodizations)) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: too many apodization functions requested\n", e->inbasefilename);
+					static_metadata_clear(&static_metadata);
+					return false;
+				}
+				else {
+					safe_strncat(apodizations, options.compression_settings[ic].value.t_string, sizeof(apodizations));
+					safe_strncat(apodizations, ";", sizeof(apodizations));
+				}
+				break;
+			case CST_MAX_LPC_ORDER:
+				FLAC__stream_encoder_set_max_lpc_order(e->encoder, options.compression_settings[ic].value.t_unsigned);
+				break;
+			case CST_QLP_COEFF_PRECISION:
+				FLAC__stream_encoder_set_qlp_coeff_precision(e->encoder, options.compression_settings[ic].value.t_unsigned);
+				break;
+			case CST_DO_QLP_COEFF_PREC_SEARCH:
+				FLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder, options.compression_settings[ic].value.t_bool);
+				break;
+			case CST_DO_ESCAPE_CODING:
+				FLAC__stream_encoder_set_do_escape_coding(e->encoder, options.compression_settings[ic].value.t_bool);
+				break;
+			case CST_DO_EXHAUSTIVE_MODEL_SEARCH:
+				FLAC__stream_encoder_set_do_exhaustive_model_search(e->encoder, options.compression_settings[ic].value.t_bool);
+				break;
+			case CST_MIN_RESIDUAL_PARTITION_ORDER:
+				FLAC__stream_encoder_set_min_residual_partition_order(e->encoder, options.compression_settings[ic].value.t_unsigned);
+				break;
+			case CST_MAX_RESIDUAL_PARTITION_ORDER:
+				FLAC__stream_encoder_set_max_residual_partition_order(e->encoder, options.compression_settings[ic].value.t_unsigned);
+				break;
+			case CST_RICE_PARAMETER_SEARCH_DIST:
+				FLAC__stream_encoder_set_rice_parameter_search_dist(e->encoder, options.compression_settings[ic].value.t_unsigned);
+				break;
+		}
+	}
+	if(*apodizations)
+		FLAC__stream_encoder_set_apodization(e->encoder, apodizations);
+	FLAC__stream_encoder_set_total_samples_estimate(e->encoder, e->total_samples_to_encode);
+	FLAC__stream_encoder_set_metadata(e->encoder, (num_metadata > 0)? metadata : 0, num_metadata);
+
+	FLAC__stream_encoder_disable_constant_subframes(e->encoder, options.debug.disable_constant_subframes);
+	FLAC__stream_encoder_disable_fixed_subframes(e->encoder, options.debug.disable_fixed_subframes);
+	FLAC__stream_encoder_disable_verbatim_subframes(e->encoder, options.debug.disable_verbatim_subframes);
+	if(!options.debug.do_md5) {
+		flac__utils_printf(stderr, 1, "%s: WARNING, MD5 computation disabled, resulting file will not have MD5 sum\n", e->inbasefilename);
+		if(e->treat_warnings_as_errors) {
+			static_metadata_clear(&static_metadata);
+			return false;
+		}
+		FLAC__stream_encoder_set_do_md5(e->encoder, false);
+	}
+
+#if FLAC__HAS_OGG
+	if(e->use_ogg) {
+		FLAC__stream_encoder_set_ogg_serial_number(e->encoder, options.serial_number);
+
+		init_status = FLAC__stream_encoder_init_ogg_file(e->encoder, e->is_stdout? 0 : e->outfilename, encoder_progress_callback, /*client_data=*/e);
+	}
+	else
+#endif
+	{
+		init_status = FLAC__stream_encoder_init_file(e->encoder, e->is_stdout? 0 : e->outfilename, encoder_progress_callback, /*client_data=*/e);
+	}
+
+	if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+		print_error_with_init_status(e, "ERROR initializing encoder", init_status);
+		if(FLAC__stream_encoder_get_state(e->encoder) != FLAC__STREAM_ENCODER_IO_ERROR)
+			e->outputfile_opened = true;
+		static_metadata_clear(&static_metadata);
+		return false;
+	}
+	else
+		e->outputfile_opened = true;
+
+	e->stats_frames_interval =
+		(FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) && FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x1f :
+		(FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) || FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x3f :
+		0xff;
+
+	static_metadata_clear(&static_metadata);
+
+	return true;
+}
+
+FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], uint32_t samples)
+{
+	if(e->replay_gain) {
+		if(!grabbag__replaygain_analyze(buffer, e->info.channels==2, e->info.bits_per_sample, samples)) {
+			flac__utils_printf(stderr, 1, "%s: WARNING, error while calculating ReplayGain\n", e->inbasefilename);
+			if(e->treat_warnings_as_errors)
+				return false;
+		}
+	}
+
+	return FLAC__stream_encoder_process(e->encoder, buffer, samples);
+}
+
+FLAC__bool EncoderSession_format_is_iff(const EncoderSession *e)
+{
+	return
+		e->format == FORMAT_WAVE ||
+		e->format == FORMAT_WAVE64 ||
+		e->format == FORMAT_RF64 ||
+		e->format == FORMAT_AIFF ||
+		e->format == FORMAT_AIFF_C;
+}
+
+FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e)
+{
+	const FLAC__bool only_placeholders = e->is_stdout;
+	FLAC__bool has_real_points;
+
+	if(num_requested_seek_points == 0 && 0 == cuesheet)
+		return true;
+
+	if(num_requested_seek_points < 0) {
+#if FLAC__HAS_OGG
+		/*@@@@@@ workaround ogg bug: too many seekpoints makes table not fit in one page */
+		if(e->use_ogg && e->total_samples_to_encode > 0 && e->total_samples_to_encode / e->info.sample_rate / 10 > 230)
+			requested_seek_points = "230x;";
+		else
+#endif
+			requested_seek_points = "10s;";
+		num_requested_seek_points = 1;
+	}
+
+	if(num_requested_seek_points > 0) {
+		if(!grabbag__seektable_convert_specification_to_template(requested_seek_points, only_placeholders, e->total_samples_to_encode, e->info.sample_rate, e->seek_table_template, &has_real_points))
+			return false;
+	}
+
+	if(0 != cuesheet) {
+		uint32_t i, j;
+		const FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet;
+		for(i = 0; i < cs->num_tracks; i++) {
+			const FLAC__StreamMetadata_CueSheet_Track *tr = cs->tracks+i;
+			for(j = 0; j < tr->num_indices; j++) {
+				if(!FLAC__metadata_object_seektable_template_append_point(e->seek_table_template, tr->offset + tr->indices[j].offset))
+					return false;
+				has_real_points = true;
+			}
+		}
+		if(has_real_points)
+			if(!FLAC__metadata_object_seektable_template_sort(e->seek_table_template, /*compact=*/true))
+				return false;
+	}
+
+	if(has_real_points) {
+		if(e->is_stdout) {
+			flac__utils_printf(stderr, 1, "%s: WARNING, cannot write back seekpoints when encoding to stdout\n", e->inbasefilename);
+			if(e->treat_warnings_as_errors)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input)
+{
+	/* convert from mm:ss.sss to sample number if necessary */
+	flac__utils_canonicalize_skip_until_specification(spec, sample_rate);
+
+	/* special case: if "--until=-0", use the special value '0' to mean "end-of-stream" */
+	if(spec->is_relative && spec->value.samples == 0) {
+		spec->is_relative = false;
+		return true;
+	}
+
+	/* in any other case the total samples in the input must be known */
+	if(total_samples_in_input == 0) {
+		flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until when input length is unknown\n", inbasefilename);
+		return false;
+	}
+
+	FLAC__ASSERT(spec->value_is_samples);
+
+	/* convert relative specifications to absolute */
+	if(spec->is_relative) {
+		if(spec->value.samples <= 0)
+			spec->value.samples += (FLAC__int64)total_samples_in_input;
+		else
+			spec->value.samples += skip;
+		spec->is_relative = false;
+	}
+
+	/* error check */
+	if(spec->value.samples < 0) {
+		flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before beginning of input\n", inbasefilename);
+		return false;
+	}
+	if((FLAC__uint64)spec->value.samples <= skip) {
+		flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before --skip point\n", inbasefilename);
+		return false;
+	}
+	if((FLAC__uint64)spec->value.samples > total_samples_in_input) {
+		flac__utils_printf(stderr, 1, "%s: ERROR, --until value is after end of input\n", inbasefilename);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, uint32_t num_metadata)
+{
+	FLAC__bool metadata_picture_has_type1 = false;
+	FLAC__bool metadata_picture_has_type2 = false;
+	uint32_t i;
+
+	FLAC__ASSERT(0 != metadata);
+	for(i = 0; i < num_metadata; i++) {
+		const FLAC__StreamMetadata *m = metadata[i];
+		if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+			if(!FLAC__format_seektable_is_legal(&m->data.seek_table)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: SEEKTABLE metadata block is invalid\n", e->inbasefilename);
+				return false;
+			}
+		}
+		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)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: CUESHEET metadata block is invalid\n", e->inbasefilename);
+				return false;
+			}
+		}
+		else if(m->type == FLAC__METADATA_TYPE_PICTURE) {
+			const char *error = 0;
+			if(!FLAC__format_picture_is_legal(&m->data.picture, &error)) {
+				flac__utils_printf(stderr, 1, "%s: ERROR: PICTURE metadata block is invalid: %s\n", e->inbasefilename, error);
+				return false;
+			}
+			if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
+				if(metadata_picture_has_type1) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: there may only be one picture of type 1 (32x32 icon) in the file\n", e->inbasefilename);
+					return false;
+				}
+				metadata_picture_has_type1 = true;
+			}
+			else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
+				if(metadata_picture_has_type2) {
+					flac__utils_printf(stderr, 1, "%s: ERROR: there may only be one picture of type 2 (icon) in the file\n", e->inbasefilename);
+					return false;
+				}
+				metadata_picture_has_type2 = true;
+			}
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool format_input(FLAC__int32 *dest[], uint32_t wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, uint32_t channels, uint32_t bps, uint32_t shift, size_t *channel_map)
+{
+	uint32_t wide_sample, sample, channel;
+	FLAC__int32 *out[FLAC__MAX_CHANNELS];
+
+	if(0 == channel_map) {
+		for(channel = 0; channel < channels; channel++)
+			out[channel] = dest[channel];
+	}
+	else {
+		for(channel = 0; channel < channels; channel++)
+			out[channel] = dest[channel_map[channel]];
+	}
+
+	if(bps == 8) {
+		if(is_unsigned_samples) {
+			for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+				for(channel = 0; channel < channels; channel++, sample++)
+					out[channel][wide_sample] = (FLAC__int32)ubuffer.u8[sample] - 0x80;
+		}
+		else {
+			for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+				for(channel = 0; channel < channels; channel++, sample++)
+					out[channel][wide_sample] = (FLAC__int32)ubuffer.s8[sample];
+		}
+	}
+	else if(bps == 16) {
+		if(is_big_endian != is_big_endian_host_) {
+			uint8_t tmp;
+			const uint32_t bytes = wide_samples * channels * (bps >> 3);
+			uint32_t b;
+			for(b = 0; b < bytes; b += 2) {
+				tmp = ubuffer.u8[b];
+				ubuffer.u8[b] = ubuffer.u8[b+1];
+				ubuffer.u8[b+1] = tmp;
+			}
+		}
+		if(is_unsigned_samples) {
+			for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+				for(channel = 0; channel < channels; channel++, sample++)
+					out[channel][wide_sample] = ubuffer.u16[sample] - 0x8000;
+		}
+		else {
+			for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+				for(channel = 0; channel < channels; channel++, sample++)
+					out[channel][wide_sample] = ubuffer.s16[sample];
+		}
+	}
+	else if(bps == 24) {
+		if(!is_big_endian) {
+			uint8_t tmp;
+			const uint32_t bytes = wide_samples * channels * (bps >> 3);
+			uint32_t b;
+			for(b = 0; b < bytes; b += 3) {
+				tmp = ubuffer.u8[b];
+				ubuffer.u8[b] = ubuffer.u8[b+2];
+				ubuffer.u8[b+2] = tmp;
+			}
+		}
+		if(is_unsigned_samples) {
+			uint32_t b;
+			for(b = sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+				for(channel = 0; channel < channels; channel++, sample++) {
+					uint32_t t;
+					t  = ubuffer.u8[b++]; t <<= 8;
+					t |= ubuffer.u8[b++]; t <<= 8;
+					t |= ubuffer.u8[b++];
+					out[channel][wide_sample] = (FLAC__int32)t - 0x800000;
+				}
+		}
+		else {
+			uint32_t b;
+			for(b = sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+				for(channel = 0; channel < channels; channel++, sample++) {
+					uint32_t t;
+					t  = ubuffer.s8[b++]; t <<= 8;
+					t |= ubuffer.u8[b++]; t <<= 8;
+					t |= ubuffer.u8[b++];
+					out[channel][wide_sample] = t;
+				}
+		}
+	}
+	else {
+		FLAC__ASSERT(0);
+	}
+	if(shift > 0) {
+		FLAC__int32 mask = (1<<shift)-1;
+		for(wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+			for(channel = 0; channel < channels; channel++) {
+				if(out[channel][wide_sample] & mask) {
+					flac__utils_printf(stderr, 1, "ERROR during read, sample data (channel#%u sample#%u = %d) has non-zero least-significant bits\n  WAVE/AIFF header said the last %u bits are not significant and should be zero.\n", channel, wide_sample, out[channel][wide_sample], shift);
+					return false;
+				}
+				out[channel][wide_sample] >>= shift;
+			}
+	}
+	return true;
+}
+
+void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data)
+{
+	EncoderSession *e = (EncoderSession*)client_data;
+
+	const FLAC__uint64 uesize = e->unencoded_size;
+
+	e->progress = e->total_samples_to_encode ? (double)samples_written / (double)e->total_samples_to_encode : 0;
+	e->compression_ratio = (e->progress && uesize) ? (double)e->bytes_written / ((double)uesize * min(1.0, e->progress)) : 0;
+
+	(void)encoder, (void)total_frames_estimate;
+
+	e->bytes_written = bytes_written;
+	e->samples_written = samples_written;
+
+	if(e->total_samples_to_encode > 0 && frames_written - e->old_frames_written > e->stats_frames_interval) {
+		print_stats(e);
+		e->old_frames_written = frames_written;
+	}
+}
+
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	size_t n = 0;
+	EncoderSession *e = (EncoderSession*)client_data;
+	FLACDecoderData *data = &e->fmt.flac.client_data;
+
+	(void)decoder;
+
+	if (data->fatal_error)
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+	/* use up lookahead first */
+	if (data->lookahead_length) {
+		n = min(data->lookahead_length, *bytes);
+		memcpy(buffer, data->lookahead, n);
+		buffer += n;
+		data->lookahead += n;
+		data->lookahead_length -= n;
+	}
+
+	/* get the rest from file */
+	if (*bytes > n) {
+		*bytes = n + fread(buffer, 1, *bytes-n, e->fin);
+		if(ferror(e->fin))
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		else if(0 == *bytes)
+			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;
+}
+
+FLAC__StreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	EncoderSession *e = (EncoderSession*)client_data;
+	(void)decoder;
+
+	if(fseeko(e->fin, (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 flac_decoder_tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	EncoderSession *e = (EncoderSession*)client_data;
+	FLAC__off_t pos;
+	(void)decoder;
+
+	if((pos = ftello(e->fin)) < 0)
+		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+	else {
+		*absolute_byte_offset = (FLAC__uint64)pos;
+		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+	}
+}
+
+FLAC__StreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+	const EncoderSession *e = (EncoderSession*)client_data;
+	const FLACDecoderData *data = &e->fmt.flac.client_data;
+	(void)decoder;
+
+	if(data->filesize < 0)
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+	else {
+		*stream_length = (FLAC__uint64)data->filesize;
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+	}
+}
+
+FLAC__bool flac_decoder_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+	EncoderSession *e = (EncoderSession*)client_data;
+	(void)decoder;
+
+	return feof(e->fin)? true : false;
+}
+
+FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	EncoderSession *e = (EncoderSession*)client_data;
+	FLACDecoderData *data = &e->fmt.flac.client_data;
+	FLAC__uint64 n = min(data->samples_left_to_process, frame->header.blocksize);
+	(void)decoder;
+
+	if(!EncoderSession_process(e, buffer, (uint32_t)n)) {
+		print_error_with_state(e, "ERROR during encoding");
+		data->fatal_error = true;
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	data->samples_left_to_process -= n;
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	EncoderSession *e = (EncoderSession*)client_data;
+	FLACDecoderData *data = &e->fmt.flac.client_data;
+	(void)decoder;
+
+	if (data->fatal_error)
+		return;
+
+	if (
+		data->num_metadata_blocks == sizeof(data->metadata_blocks)/sizeof(data->metadata_blocks[0]) ||
+		0 == (data->metadata_blocks[data->num_metadata_blocks] = FLAC__metadata_object_clone(metadata))
+	)
+		data->fatal_error = true;
+	else
+		data->num_metadata_blocks++;
+}
+
+void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	EncoderSession *e = (EncoderSession*)client_data;
+	FLACDecoderData *data = &e->fmt.flac.client_data;
+	(void)decoder;
+
+	stats_print_name(1, e->inbasefilename);
+	flac__utils_printf(stderr, 1, "ERROR got %s while decoding FLAC input\n", FLAC__StreamDecoderErrorStatusString[status]);
+	if(!e->continue_through_decode_errors)
+		data->fatal_error = true;
+}
+
+FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors)
+{
+	FILE *f;
+	uint32_t last_line_read;
+	const char *error_message;
+
+	if(0 == cuesheet_filename)
+		return true;
+
+	if(lead_out_offset == 0) {
+		flac__utils_printf(stderr, 1, "%s: ERROR cannot import cuesheet when the number of input samples to encode is unknown\n", inbasefilename);
+		return false;
+	}
+
+	if(0 == (f = flac_fopen(cuesheet_filename, "r"))) {
+		flac__utils_printf(stderr, 1, "%s: ERROR opening cuesheet \"%s\" for reading: %s\n", inbasefilename, cuesheet_filename, strerror(errno));
+		return false;
+	}
+
+	*cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset);
+
+	fclose(f);
+
+	if(0 == *cuesheet) {
+		flac__utils_printf(stderr, 1, "%s: ERROR parsing cuesheet \"%s\" on line %u: %s\n", inbasefilename, cuesheet_filename, last_line_read, error_message);
+		return false;
+	}
+
+	if(!FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/false, &error_message)) {
+		flac__utils_printf(stderr, 1, "%s: ERROR parsing cuesheet \"%s\": %s\n", inbasefilename, cuesheet_filename, error_message);
+		return false;
+	}
+
+	/* if we're expecting CDDA, warn about non-compliance */
+	if(is_cdda && !FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/true, &error_message)) {
+		flac__utils_printf(stderr, 1, "%s: WARNING cuesheet \"%s\" is not audio CD compliant: %s\n", inbasefilename, cuesheet_filename, error_message);
+		if(treat_warnings_as_errors)
+			return false;
+		(*cuesheet)->data.cue_sheet.is_cd = false;
+	}
+
+	return true;
+}
+
+static void print_stats(const EncoderSession *encoder_session)
+{
+	if(flac__utils_verbosity_ >= 2) {
+		char ratiostr[16];
+
+		FLAC__ASSERT(encoder_session->total_samples_to_encode > 0);
+
+		if (encoder_session->compression_ratio > 0.0)
+			flac_snprintf(ratiostr, sizeof(ratiostr), "%0.3f", encoder_session->compression_ratio);
+		else
+			flac_snprintf(ratiostr, sizeof(ratiostr), "N/A");
+
+		if(encoder_session->samples_written == encoder_session->total_samples_to_encode) {
+			stats_print_name(2, encoder_session->inbasefilename);
+			stats_print_info(2, "%swrote %" PRIu64 " bytes, ratio=%s",
+				encoder_session->verify? "Verify OK, " : "",
+				encoder_session->bytes_written,
+				ratiostr
+			);
+		}
+		else {
+			stats_print_name(2, encoder_session->inbasefilename);
+			stats_print_info(2, "%u%% complete, ratio=%s", (uint32_t)floor(encoder_session->progress * 100.0 + 0.5), ratiostr);
+		}
+	}
+}
+
+void print_error_with_init_status(const EncoderSession *e, const char *message, FLAC__StreamEncoderInitStatus init_status)
+{
+	const int ilen = strlen(e->inbasefilename) + 1;
+	const char *state_string = "";
+
+	flac__utils_printf(stderr, 1, "\n%s: %s\n", e->inbasefilename, message);
+
+	flac__utils_printf(stderr, 1, "%*s init_status = %s\n", ilen, "", FLAC__StreamEncoderInitStatusString[init_status]);
+
+	if(init_status == FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR) {
+		state_string = FLAC__stream_encoder_get_resolved_state_string(e->encoder);
+
+		flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", state_string);
+
+		/* print out some more info for some errors: */
+		if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_CLIENT_ERROR])) {
+			flac__utils_printf(stderr, 1,
+				"\n"
+				"An error occurred while writing; the most common cause is that the disk is full.\n"
+			);
+		}
+		else if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_IO_ERROR])) {
+			flac__utils_printf(stderr, 1,
+				"\n"
+				"An error occurred opening the output file; it is likely that the output\n"
+				"directory does not exist or is not writable, the output file already exists and\n"
+				"is not writable, or the disk is full.\n"
+			);
+		}
+	}
+	else if(init_status == FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE) {
+		flac__utils_printf(stderr, 1,
+			"\n"
+			"The encoding parameters specified do not conform to the FLAC Subset and may not\n"
+			"be streamable or playable in hardware devices.  If you really understand the\n"
+			"consequences, you can add --lax to the command-line options to encode with\n"
+			"these parameters anyway.  See http://xiph.org/flac/format.html#subset\n"
+		);
+	}
+}
+
+void print_error_with_state(const EncoderSession *e, const char *message)
+{
+	const int ilen = strlen(e->inbasefilename) + 1;
+	const char *state_string;
+
+	flac__utils_printf(stderr, 1, "\n%s: %s\n", e->inbasefilename, message);
+
+	state_string = FLAC__stream_encoder_get_resolved_state_string(e->encoder);
+
+	flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", state_string);
+
+	/* print out some more info for some errors: */
+	if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_CLIENT_ERROR])) {
+		flac__utils_printf(stderr, 1,
+			"\n"
+			"An error occurred while writing; the most common cause is that the disk is full.\n"
+		);
+	}
+}
+
+void print_verify_error(EncoderSession *e)
+{
+	FLAC__uint64 absolute_sample;
+	uint32_t frame_number;
+	uint32_t channel;
+	uint32_t sample;
+	FLAC__int32 expected;
+	FLAC__int32 got;
+
+	FLAC__stream_encoder_get_verify_decoder_error_stats(e->encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+
+	flac__utils_printf(stderr, 1, "%s: ERROR: mismatch in decoded data, verify FAILED!\n", e->inbasefilename);
+	flac__utils_printf(stderr, 1, "       Absolute sample=%" PRIu64 ", frame=%u, channel=%u, sample=%u, expected %d, got %d\n", absolute_sample, frame_number, channel, sample, expected, got);
+	flac__utils_printf(stderr, 1, "       In all known cases, verify errors are caused by hardware problems,\n");
+	flac__utils_printf(stderr, 1, "       usually overclocking or bad RAM.  Delete %s\n", e->outfilename);
+	flac__utils_printf(stderr, 1, "       and repeat the flac command exactly as before.  If it does not give a\n");
+	flac__utils_printf(stderr, 1, "       verify error in the exact same place each time you try it, then there is\n");
+	flac__utils_printf(stderr, 1, "       a problem with your hardware; please see the FAQ:\n");
+	flac__utils_printf(stderr, 1, "           http://xiph.org/flac/faq.html#tools__hardware_prob\n");
+	flac__utils_printf(stderr, 1, "       If it does fail in the exact same place every time, keep\n");
+	flac__utils_printf(stderr, 1, "       %s and submit a bug report to:\n", e->outfilename);
+	flac__utils_printf(stderr, 1, "           https://sourceforge.net/p/flac/bugs/\n");
+	flac__utils_printf(stderr, 1, "       Make sure to upload the FLAC file and use the \"Monitor\" feature to\n");
+	flac__utils_printf(stderr, 1, "       monitor the bug status.\n");
+	flac__utils_printf(stderr, 1, "Verify FAILED!  Do not trust %s\n", e->outfilename);
+}
+
+FLAC__bool read_bytes(FILE *f, FLAC__byte *buf, size_t n, FLAC__bool eof_ok, const char *fn)
+{
+	size_t bytes_read = fread(buf, 1, n, f);
+
+	if(bytes_read == 0) {
+		if(!eof_ok) {
+			flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+			return false;
+		}
+		else
+			return true;
+	}
+	if(bytes_read < n) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+		return false;
+	}
+	return true;
+}
+
+FLAC__bool read_uint16(FILE *f, FLAC__bool big_endian, FLAC__uint16 *val, const char *fn)
+{
+	if(!read_bytes(f, (FLAC__byte*)val, 2, /*eof_ok=*/false, fn))
+		return false;
+	if(is_big_endian_host_ != big_endian) {
+		FLAC__byte tmp, *b = (FLAC__byte*)val;
+		tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+	}
+	return true;
+}
+
+FLAC__bool read_uint32(FILE *f, FLAC__bool big_endian, FLAC__uint32 *val, const char *fn)
+{
+	if(!read_bytes(f, (FLAC__byte*)val, 4, /*eof_ok=*/false, fn))
+		return false;
+	if(is_big_endian_host_ != big_endian) {
+		FLAC__byte tmp, *b = (FLAC__byte*)val;
+		tmp = b[3]; b[3] = b[0]; b[0] = tmp;
+		tmp = b[2]; b[2] = b[1]; b[1] = tmp;
+	}
+	return true;
+}
+
+FLAC__bool read_uint64(FILE *f, FLAC__bool big_endian, FLAC__uint64 *val, const char *fn)
+{
+	if(!read_bytes(f, (FLAC__byte*)val, 8, /*eof_ok=*/false, fn))
+		return false;
+	if(is_big_endian_host_ != big_endian) {
+		FLAC__byte tmp, *b = (FLAC__byte*)val;
+		tmp = b[7]; b[7] = b[0]; b[0] = tmp;
+		tmp = b[6]; b[6] = b[1]; b[1] = tmp;
+		tmp = b[5]; b[5] = b[2]; b[2] = tmp;
+		tmp = b[4]; b[4] = b[3]; b[3] = tmp;
+	}
+	return true;
+}
+
+FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, const char *fn)
+	/* Read an IEEE 754 80-bit (aka SANE) extended floating point value from 'f',
+	 * convert it into an integral value and store in 'val'.  Return false if only
+	 * between 1 and 9 bytes remain in 'f', if 0 bytes remain in 'f', or if the
+	 * value is negative, between zero and one, or too large to be represented by
+	 * 'val'; return true otherwise.
+	 */
+{
+	uint32_t i;
+	FLAC__byte buf[10];
+	FLAC__uint64 p = 0;
+	FLAC__int16 e;
+	FLAC__int16 shift;
+
+	if(!read_bytes(f, buf, sizeof(buf), /*eof_ok=*/false, fn))
+		return false;
+	e = ((FLAC__uint16)(buf[0])<<8 | (FLAC__uint16)(buf[1]))-0x3FFF;
+	shift = 63-e;
+	if((buf[0]>>7)==1U || e<0 || e>63) {
+		flac__utils_printf(stderr, 1, "%s: ERROR: invalid floating-point value\n", fn);
+		return false;
+	}
+
+	for(i = 0; i < 8; ++i)
+		p |= (FLAC__uint64)(buf[i+2])<<(56U-i*8);
+	*val = (FLAC__uint32)((p>>shift)+(p>>(shift-1) & 0x1));
+
+	return true;
+}
+
+FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset)
+{
+	static uint8_t dump[8192];
+	struct flac_stat_s stb;
+
+	if(flac_fstat(fileno(f), &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFREG)
+	{
+		if(fseeko(f, offset, SEEK_CUR) == 0)
+			return true;
+	}
+	while(offset > 0) {
+		const long need = (long)min(offset, sizeof(dump));
+		if((long)fread(dump, 1, need, f) < need)
+			return false;
+		offset -= need;
+	}
+	return true;
+}
+
+uint32_t count_channel_mask_bits(FLAC__uint32 mask)
+{
+	uint32_t count = 0;
+	while(mask) {
+		if(mask & 1)
+			count++;
+		mask >>= 1;
+	}
+	return count;
+}
+
+#if 0
+FLAC__uint32 limit_channel_mask(FLAC__uint32 mask, uint32_t channels)
+{
+	FLAC__uint32 x = 0x80000000;
+	uint32_t count = count_channel_mask_bits(mask);
+	while(x && count > channels) {
+		if(mask & x) {
+			mask &= ~x;
+			count--;
+		}
+		x >>= 1;
+	}
+	FLAC__ASSERT(count_channel_mask_bits(mask) == channels);
+	return mask;
+}
+#endif
diff --git a/src/flac/encode.h b/src/flac/encode.h
new file mode 100644
index 0000000..b98bef6
--- /dev/null
+++ b/src/flac/encode.h
@@ -0,0 +1,117 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__encode_h
+#define flac__encode_h
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "foreign_metadata.h"
+#include "utils.h"
+#include "share/compat.h"
+
+extern const int FLAC_ENCODE__DEFAULT_PADDING;
+
+typedef enum {
+	CST_BLOCKSIZE,
+	CST_COMPRESSION_LEVEL,
+	CST_DO_MID_SIDE,
+	CST_LOOSE_MID_SIDE,
+	CST_APODIZATION,
+	CST_MAX_LPC_ORDER,
+	CST_QLP_COEFF_PRECISION,
+	CST_DO_QLP_COEFF_PREC_SEARCH,
+	CST_DO_ESCAPE_CODING,
+	CST_DO_EXHAUSTIVE_MODEL_SEARCH,
+	CST_MIN_RESIDUAL_PARTITION_ORDER,
+	CST_MAX_RESIDUAL_PARTITION_ORDER,
+	CST_RICE_PARAMETER_SEARCH_DIST
+} compression_setting_type_t;
+
+typedef struct {
+	compression_setting_type_t type;
+	union {
+		FLAC__bool t_bool;
+		unsigned t_unsigned;
+		const char *t_string;
+	} value;
+} compression_setting_t;
+
+typedef struct {
+	utils__SkipUntilSpecification skip_specification;
+	utils__SkipUntilSpecification until_specification;
+	FLAC__bool verify;
+#if FLAC__HAS_OGG
+	FLAC__bool use_ogg;
+	long serial_number;
+#endif
+	FLAC__bool lax;
+	int padding;
+	size_t num_compression_settings;
+	compression_setting_t compression_settings[64];
+	char *requested_seek_points;
+	int num_requested_seek_points;
+	const char *cuesheet_filename;
+	FLAC__bool treat_warnings_as_errors;
+	FLAC__bool continue_through_decode_errors; /* currently only obeyed when encoding from FLAC or Ogg FLAC */
+	FLAC__bool cued_seekpoints;
+	FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */
+
+	/* options related to --replay-gain and --sector-align */
+	FLAC__bool is_first_file;
+	FLAC__bool is_last_file;
+	FLAC__int32 **align_reservoir;
+	unsigned *align_reservoir_samples;
+	FLAC__bool replay_gain;
+	FLAC__bool ignore_chunk_sizes;
+	FLAC__bool sector_align;
+	FLAC__bool error_on_compression_fail;
+
+	FLAC__StreamMetadata *vorbis_comment;
+	FLAC__StreamMetadata *pictures[64];
+	unsigned num_pictures;
+
+	FileFormat format;
+	union {
+		struct {
+			FLAC__bool is_big_endian;
+			FLAC__bool is_unsigned_samples;
+			unsigned channels;
+			unsigned bps;
+			unsigned sample_rate;
+		} raw;
+		struct {
+			foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */
+		} iff;
+	} format_options;
+
+	struct {
+		FLAC__bool disable_constant_subframes;
+		FLAC__bool disable_fixed_subframes;
+		FLAC__bool disable_verbatim_subframes;
+		FLAC__bool do_md5;
+	} debug;
+} encode_options_t;
+
+int flac__encode_file(FILE *infile, FLAC__off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length, encode_options_t options);
+
+#endif
diff --git a/src/flac/flac.vcproj b/src/flac/flac.vcproj
new file mode 100644
index 0000000..0c962b1
--- /dev/null
+++ b/src/flac/flac.vcproj
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="flac"

+	ProjectGUID="{4cefbc7d-c215-11db-8314-0800200c9a66}"

+	RootNamespace="flac"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\analyze.h"

+				>

+			</File>

+			<File

+				RelativePath=".\decode.h"

+				>

+			</File>

+			<File

+				RelativePath=".\encode.h"

+				>

+			</File>

+			<File

+				RelativePath=".\foreign_metadata.h"

+				>

+			</File>

+			<File

+				RelativePath=".\local_string_utils.h"

+				>

+			</File>

+			<File

+				RelativePath=".\utils.h"

+				>

+			</File>

+			<File

+				RelativePath=".\vorbiscomment.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\analyze.c"

+				>

+			</File>

+			<File

+				RelativePath=".\decode.c"

+				>

+			</File>

+			<File

+				RelativePath=".\encode.c"

+				>

+			</File>

+			<File

+				RelativePath=".\foreign_metadata.c"

+				>

+			</File>

+			<File

+				RelativePath=".\local_string_utils.c"

+				>

+			</File>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+			<File

+				RelativePath=".\utils.c"

+				>

+			</File>

+			<File

+				RelativePath=".\vorbiscomment.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/flac/flac.vcxproj b/src/flac/flac.vcxproj
new file mode 100644
index 0000000..ac7f4ea
--- /dev/null
+++ b/src/flac/flac.vcxproj
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc7d-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>flac</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="analyze.h" />

+    <ClInclude Include="decode.h" />

+    <ClInclude Include="encode.h" />

+    <ClInclude Include="foreign_metadata.h" />

+    <ClInclude Include="local_string_utils.h" />

+    <ClInclude Include="utils.h" />

+    <ClInclude Include="vorbiscomment.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="analyze.c" />

+    <ClCompile Include="decode.c" />

+    <ClCompile Include="encode.c" />

+    <ClCompile Include="foreign_metadata.c" />

+    <ClCompile Include="local_string_utils.c" />

+    <ClCompile Include="main.c" />

+    <ClCompile Include="utils.c" />

+    <ClCompile Include="vorbiscomment.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\getopt\getopt_static.vcxproj">

+      <Project>{4cefbc80-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\grabbag\grabbag_static.vcxproj">

+      <Project>{4cefbc81-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\replaygain_analysis\replaygain_analysis_static.vcxproj">

+      <Project>{4cefbc89-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\replaygain_synthesis\replaygain_synthesis_static.vcxproj">

+      <Project>{4cefbc8a-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\utf8\utf8_static.vcxproj">

+      <Project>{4cefbc92-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\win_utf8_io\win_utf8_io_static.vcxproj">

+      <Project>{4cefbe02-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/flac/flac.vcxproj.filters b/src/flac/flac.vcxproj.filters
new file mode 100644
index 0000000..c46ad4c
--- /dev/null
+++ b/src/flac/flac.vcxproj.filters
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="analyze.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="decode.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="encode.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="foreign_metadata.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="local_string_utils.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="utils.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="vorbiscomment.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="analyze.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="decode.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="encode.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="foreign_metadata.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="local_string_utils.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="utils.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="vorbiscomment.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/flac/foreign_metadata.c b/src/flac/foreign_metadata.c
new file mode 100644
index 0000000..9ad9c18
--- /dev/null
+++ b/src/flac/foreign_metadata.c
@@ -0,0 +1,819 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h> /* for FILE etc. */
+#include <stdlib.h> /* for calloc() etc. */
+#include <string.h> /* for memcmp() etc. */
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "foreign_metadata.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+
+static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[3] = { "aiff" , "riff", "w64 " };
+
+static FLAC__uint32 unpack32be_(const FLAC__byte *b)
+{
+	return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3];
+}
+
+static FLAC__uint32 unpack32le_(const FLAC__byte *b)
+{
+	return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24);
+}
+
+static FLAC__uint64 unpack64le_(const FLAC__byte *b)
+{
+	return (FLAC__uint64)b[0] + ((FLAC__uint64)b[1]<<8) + ((FLAC__uint64)b[2]<<16) + ((FLAC__uint64)b[3]<<24) + ((FLAC__uint64)b[4]<<32) + ((FLAC__uint64)b[5]<<40) + ((FLAC__uint64)b[6]<<48) + ((FLAC__uint64)b[7]<<56);
+}
+
+/* copies 'size' bytes from file 'fin' to 'fout', filling in *error with 'read_error' or 'write_error' as necessary */
+static FLAC__bool copy_data_(FILE *fin, FILE *fout, size_t size, const char **error, const char * const read_error, const char * const write_error)
+{
+	FLAC__byte buffer[4096];
+	size_t left;
+	for(left = size; left > 0; ) {
+		size_t need = min(sizeof(buffer), left);
+		if(fread(buffer, 1, need, fin) < need) {
+			if(error) *error = read_error;
+			return false;
+		}
+		if(fwrite(buffer, 1, need, fout) < need) {
+			if(error) *error = write_error;
+			return false;
+		}
+		left -= need;
+	}
+	return true;
+}
+
+static FLAC__bool append_block_(foreign_metadata_t *fm, FLAC__off_t offset, FLAC__uint32 size, const char **error)
+{
+	foreign_block_t *fb = safe_realloc_muladd2_(fm->blocks, sizeof(foreign_block_t), /*times (*/fm->num_blocks, /*+*/1/*)*/);
+	if(fb) {
+		fb[fm->num_blocks].offset = offset;
+		fb[fm->num_blocks].size = size;
+		fm->num_blocks++;
+		fm->blocks = fb;
+		return true;
+	}
+	if(error) *error = "out of memory";
+	return false;
+}
+
+static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char **error)
+{
+	FLAC__byte buffer[12];
+	FLAC__off_t offset, eof_offset;
+	if((offset = ftello(f)) < 0) {
+		if(error) *error = "ftello() error (001)";
+		return false;
+	}
+	if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "FORM", 4) || (memcmp(buffer+8, "AIFF", 4) && memcmp(buffer+8, "AIFC", 4))) {
+		if(error) *error = "unsupported FORM layout (002)";
+		return false;
+	}
+	if(!append_block_(fm, offset, 12, error))
+		return false;
+	eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32be_(buffer+4);
+	while(!feof(f)) {
+		FLAC__uint32 size;
+		if((offset = ftello(f)) < 0) {
+			if(error) *error = "ftello() error (003)";
+			return false;
+		}
+		if((size = fread(buffer, 1, 8, f)) < 8) {
+			if(size == 0 && feof(f))
+				break;
+			if(error) *error = "invalid AIFF file (004)";
+			return false;
+		}
+		size = unpack32be_(buffer+4);
+		/* check if pad byte needed */
+		if(size & 1)
+			size++;
+		if(!memcmp(buffer, "COMM", 4)) {
+			if(fm->format_block) {
+				if(error) *error = "invalid AIFF file: multiple \"COMM\" chunks (005)";
+				return false;
+			}
+			if(fm->audio_block) {
+				if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
+				return false;
+			}
+			fm->format_block = fm->num_blocks;
+		}
+		else if(!memcmp(buffer, "SSND", 4)) {
+			if(fm->audio_block) {
+				if(error) *error = "invalid AIFF file: multiple \"SSND\" chunks (007)";
+				return false;
+			}
+			if(!fm->format_block) {
+				if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
+				return false;
+			}
+			fm->audio_block = fm->num_blocks;
+			/* read #offset bytes */
+			if(fread(buffer+8, 1, 4, f) < 4) {
+				if(error) *error = "invalid AIFF file (009)";
+				return false;
+			}
+			fm->ssnd_offset_size = unpack32be_(buffer+8);
+			if(fseeko(f, -4, SEEK_CUR) < 0) {
+				if(error) *error = "invalid AIFF file: seek error (010)";
+				return false;
+			}
+			/* WATCHOUT: For SSND we ignore the blockSize and are not saving any
+			 * unaligned part at the end of the chunk.  In retrospect it is pretty
+			 * pointless to save the unaligned data before the PCM but now it is
+			 * done and cast in stone.
+			 */
+		}
+		if(!append_block_(fm, offset, 8 + (memcmp(buffer, "SSND", 4)? size : 8 + fm->ssnd_offset_size), error))
+			return false;
+		/* skip to next chunk */
+		if(fseeko(f, size, SEEK_CUR) < 0) {
+			if(error) *error = "invalid AIFF file: seek error (011)";
+			return false;
+		}
+	}
+	if(eof_offset != ftello(f)) {
+		if(error) *error = "invalid AIFF file: unexpected EOF (012)";
+		return false;
+	}
+	if(!fm->format_block) {
+		if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)";
+		return false;
+	}
+	if(!fm->audio_block) {
+		if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)";
+		return false;
+	}
+	return true;
+}
+
+static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error)
+{
+	FLAC__byte buffer[12];
+	FLAC__off_t offset, eof_offset = -1, ds64_data_size = -1;
+	if((offset = ftello(f)) < 0) {
+		if(error) *error = "ftello() error (001)";
+		return false;
+	}
+	if(fread(buffer, 1, 12, f) < 12 || (memcmp(buffer, "RIFF", 4) && memcmp(buffer, "RF64", 4)) || memcmp(buffer+8, "WAVE", 4)) {
+		if(error) *error = "unsupported RIFF layout (002)";
+		return false;
+	}
+	if(!memcmp(buffer, "RF64", 4))
+		fm->is_rf64 = true;
+	if(fm->is_rf64 && sizeof(FLAC__off_t) < 8) {
+		if(error) *error = "RF64 is not supported on this compile (r00)";
+		return false;
+	}
+	if(!append_block_(fm, offset, 12, error))
+		return false;
+	if(!fm->is_rf64 || unpack32le_(buffer+4) != 0xffffffff) {
+		eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32le_(buffer+4);
+		if(eof_offset & 1) /* fix odd RIFF size */
+			eof_offset++;
+	}
+	while(!feof(f)) {
+		FLAC__uint32 size;
+		if((offset = ftello(f)) < 0) {
+			if(error) *error = "ftello() error (003)";
+			return false;
+		}
+		if((size = fread(buffer, 1, 8, f)) < 8) {
+			if(size == 0 && feof(f))
+				break;
+			if(error) *error = "invalid WAVE file (004)";
+			return false;
+		}
+		size = unpack32le_(buffer+4);
+		/* check if pad byte needed */
+		if(size & 1)
+			size++;
+		if(!memcmp(buffer, "fmt ", 4)) {
+			if(fm->format_block) {
+				if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)";
+				return false;
+			}
+			if(fm->audio_block) {
+				if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
+				return false;
+			}
+			fm->format_block = fm->num_blocks;
+		}
+		else if(!memcmp(buffer, "data", 4)) {
+			if(fm->audio_block) {
+				if(error) *error = "invalid WAVE file: multiple \"data\" chunks (007)";
+				return false;
+			}
+			if(!fm->format_block) {
+				if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
+				return false;
+			}
+			fm->audio_block = fm->num_blocks;
+			if(fm->is_rf64 && fm->num_blocks < 2) {
+				if(error) *error = "invalid RF64 file: \"data\" chunk before \"ds64\" chunk (r01)";
+				return false;
+			}
+		}
+		if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
+			return false;
+		/* parse ds64 chunk if necessary */
+		if(fm->is_rf64 && fm->num_blocks == 2) {
+			FLAC__byte buffer2[7*4];
+			if(memcmp(buffer, "ds64", 4)) {
+				if(error) *error = "invalid RF64 file: \"ds64\" chunk does not immediately follow \"WAVE\" marker (r02)";
+				return false;
+			}
+			/* unpack the size again since we don't want the padding byte effect */
+			size = unpack32le_(buffer+4);
+			if(size < sizeof(buffer2)) {
+				if(error) *error = "invalid RF64 file: \"ds64\" chunk size is < 28 (r03)";
+				return false;
+			}
+			if(size > sizeof(buffer2)) {
+				if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)";
+				return false;
+			}
+			if(fread(buffer2, 1, sizeof(buffer2), f) < sizeof(buffer2)) {
+				if(error) *error = "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)";
+				return false;
+			}
+			ds64_data_size = (FLAC__off_t)unpack64le_(buffer2+8);
+			if(ds64_data_size == (FLAC__off_t)(-1)) {
+				if(error) *error = "RF64 file has \"ds64\" chunk with data size == -1 (r08)";
+				return false;
+			}
+			/* check if pad byte needed */
+			if(ds64_data_size & 1)
+				ds64_data_size++;
+			/* @@@ [2^63 limit] */
+			if(ds64_data_size < 0) {
+				if(error) *error = "RF64 file too large (r09)";
+				return false;
+			}
+			if(unpack32le_(buffer2+24)) {
+				if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)";
+				return false;
+			}
+			eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack64le_(buffer2);
+			/* @@@ [2^63 limit] */
+			if((FLAC__off_t)unpack64le_(buffer2) < 0 || eof_offset < 0) {
+				if(error) *error = "RF64 file too large (r07)";
+				return false;
+			}
+		}
+		else { /* skip to next chunk */
+			if(fm->is_rf64 && !memcmp(buffer, "data", 4) && unpack32le_(buffer+4) == 0xffffffff) {
+				if(fseeko(f, ds64_data_size, SEEK_CUR) < 0) {
+					if(error) *error = "invalid RF64 file: seek error (r10)";
+					return false;
+				}
+			}
+			else {
+				if(fseeko(f, size, SEEK_CUR) < 0) {
+					if(error) *error = "invalid WAVE file: seek error (009)";
+					return false;
+				}
+			}
+		}
+	}
+	if(fm->is_rf64 && eof_offset == (FLAC__off_t)(-1)) {
+		if(error) *error = "invalid RF64 file: all RIFF sizes are -1 (r11)";
+		return false;
+	}
+	if(eof_offset != ftello(f)) {
+		if(error) *error = "invalid WAVE file: unexpected EOF (010)";
+		return false;
+	}
+	if(!fm->format_block) {
+		if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)";
+		return false;
+	}
+	if(!fm->audio_block) {
+		if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)";
+		return false;
+	}
+	return true;
+}
+
+static FLAC__bool read_from_wave64_(foreign_metadata_t *fm, FILE *f, const char **error)
+{
+	FLAC__byte buffer[40];
+	FLAC__off_t offset, eof_offset = -1;
+	if((offset = ftello(f)) < 0) {
+		if(error) *error = "ftello() error (001)";
+		return false;
+	}
+	if(
+		fread(buffer, 1, 40, f) < 40 ||
+		/* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
+		memcmp(buffer, "\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 16) ||
+		/* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
+		memcmp(buffer+24, "\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)
+	) {
+		if(error) *error = "unsupported Wave64 layout (002)";
+		return false;
+	}
+	if(sizeof(FLAC__off_t) < 8) {
+		if(error) *error = "Wave64 is not supported on this compile (r00)";
+		return false;
+	}
+	if(!append_block_(fm, offset, 40, error))
+		return false;
+	eof_offset = (FLAC__off_t)unpack64le_(buffer+16); /*@@@ [2^63 limit] */
+	while(!feof(f)) {
+		FLAC__uint64 size;
+		if((offset = ftello(f)) < 0) {
+			if(error) *error = "ftello() error (003)";
+			return false;
+		}
+		if((size = fread(buffer, 1, 24, f)) < 24) {
+			if(size == 0 && feof(f))
+				break;
+			if(error) *error = "invalid Wave64 file (004)";
+			return false;
+		}
+		size = unpack64le_(buffer+16);
+		/* check if pad bytes needed */
+		if(size & 7)
+			size = (size+7) & (~((FLAC__uint64)7));
+		/* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
+		if(!memcmp(buffer, "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
+			if(fm->format_block) {
+				if(error) *error = "invalid Wave64 file: multiple \"fmt \" chunks (005)";
+				return false;
+			}
+			if(fm->audio_block) {
+				if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
+				return false;
+			}
+			fm->format_block = fm->num_blocks;
+		}
+		/* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
+		else if(!memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
+			if(fm->audio_block) {
+				if(error) *error = "invalid Wave64 file: multiple \"data\" chunks (007)";
+				return false;
+			}
+			if(!fm->format_block) {
+				if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
+				return false;
+			}
+			fm->audio_block = fm->num_blocks;
+		}
+		if(!append_block_(fm, offset, memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)? (FLAC__uint32)size : 16+8, error))
+			return false;
+		/* skip to next chunk */
+		if(fseeko(f, size-24, SEEK_CUR) < 0) {
+			if(error) *error = "invalid Wave64 file: seek error (009)";
+			return false;
+		}
+	}
+	if(eof_offset != ftello(f)) {
+		if(error) *error = "invalid Wave64 file: unexpected EOF (010)";
+		return false;
+	}
+	if(!fm->format_block) {
+		if(error) *error = "invalid Wave64 file: missing \"fmt \" chunk (011)";
+		return false;
+	}
+	if(!fm->audio_block) {
+		if(error) *error = "invalid Wave64 file: missing \"data\" chunk (012)";
+		return false;
+	}
+	return true;
+}
+
+static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__Metadata_SimpleIterator *it, const char **error)
+{
+	FLAC__byte buffer[4];
+	const uint32_t ID_LEN = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
+	size_t block_num = 0;
+	FLAC__ASSERT(sizeof(buffer) >= ID_LEN);
+	while(block_num < fm->num_blocks) {
+		/* find next matching padding block */
+		do {
+			/* even on the first chunk's loop there will be a skippable STREAMINFO block, on subsequent loops we are first moving past the PADDING we just used */
+			if(!FLAC__metadata_simple_iterator_next(it)) {
+				if(error) *error = "no matching PADDING block found (004)";
+				return false;
+			}
+		} while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING);
+		if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) {
+			if(error) *error = "PADDING block with wrong size found (005)";
+			return false;
+		}
+		/* transfer chunk into APPLICATION block */
+		/* first set up the file pointers */
+		if(fseeko(fin, fm->blocks[block_num].offset, SEEK_SET) < 0) {
+			if(error) *error = "seek failed in WAVE/AIFF file (006)";
+			return false;
+		}
+		if(fseeko(fout, FLAC__metadata_simple_iterator_get_block_offset(it), SEEK_SET) < 0) {
+			if(error) *error = "seek failed in FLAC file (007)";
+			return false;
+		}
+		/* update the type */
+		buffer[0] = FLAC__METADATA_TYPE_APPLICATION;
+		if(FLAC__metadata_simple_iterator_is_last(it))
+			buffer[0] |= 0x80; /*MAGIC number*/
+		if(fwrite(buffer, 1, 1, fout) < 1) {
+			if(error) *error = "write failed in FLAC file (008)";
+			return false;
+		}
+		/* length stays the same so skip over it */
+		if(fseeko(fout, FLAC__STREAM_METADATA_LENGTH_LEN/8, SEEK_CUR) < 0) {
+			if(error) *error = "seek failed in FLAC file (009)";
+			return false;
+		}
+		/* write the APPLICATION ID */
+		memcpy(buffer, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], ID_LEN);
+		if(fwrite(buffer, 1, ID_LEN, fout) < ID_LEN) {
+			if(error) *error = "write failed in FLAC file (010)";
+			return false;
+		}
+		/* transfer the foreign metadata */
+		if(!copy_data_(fin, fout, fm->blocks[block_num].size, error, "read failed in WAVE/AIFF file (011)", "write failed in FLAC file (012)"))
+			return false;
+		block_num++;
+	}
+	return true;
+}
+
+static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadata_SimpleIterator *it, const char **error)
+{
+	FLAC__byte id[4], buffer[12];
+	FLAC__off_t offset;
+	FLAC__bool type_found = false, ds64_found = false;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN == sizeof(id)*8);
+
+	while(FLAC__metadata_simple_iterator_next(it)) {
+		if(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_APPLICATION)
+			continue;
+		if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) {
+			if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)";
+			return false;
+		}
+		if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
+			continue;
+		offset = FLAC__metadata_simple_iterator_get_block_offset(it);
+		/* skip over header and app ID */
+		offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8;
+		offset += sizeof(id);
+		/* look for format or audio blocks */
+		if(fseeko(f, offset, SEEK_SET) < 0) {
+			if(error) *error = "seek error (003)";
+			return false;
+		}
+		if(fread(buffer, 1, 4, f) != 4) {
+			if(error) *error = "read error (004)";
+			return false;
+		}
+		if(fm->num_blocks == 0) { /* first block? */
+			fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4);
+			if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64))
+				type_found = true;
+			else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64 && 0 == memcmp(buffer, "riff", 4)) /* use first 4 bytes instead of whole GUID */
+				type_found = true;
+			else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4))
+				type_found = true;
+			else {
+				if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (005)";
+				return false;
+			}
+		}
+		else if(!type_found) {
+			FLAC__ASSERT(0);
+			/* double protection: */
+			if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (006)";
+			return false;
+		}
+		else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF) {
+			if(!memcmp(buffer, "fmt ", 4)) {
+				if(fm->format_block) {
+					if(error) *error = "invalid WAVE metadata: multiple \"fmt \" chunks (007)";
+					return false;
+				}
+				if(fm->audio_block) {
+					if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
+					return false;
+				}
+				fm->format_block = fm->num_blocks;
+			}
+			else if(!memcmp(buffer, "data", 4)) {
+				if(fm->audio_block) {
+					if(error) *error = "invalid WAVE metadata: multiple \"data\" chunks (009)";
+					return false;
+				}
+				if(!fm->format_block) {
+					if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
+					return false;
+				}
+				fm->audio_block = fm->num_blocks;
+			}
+			else if(fm->is_rf64 && fm->num_blocks == 1) {
+				if(memcmp(buffer, "ds64", 4)) {
+					if(error) *error = "invalid RF64 metadata: second chunk is not \"ds64\" (011)";
+					return false;
+				}
+				ds64_found = true;
+			}
+		}
+		else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64) {
+			if(!memcmp(buffer, "fmt ", 4)) { /* use first 4 bytes instead of whole GUID */
+				if(fm->format_block) {
+					if(error) *error = "invalid Wave64 metadata: multiple \"fmt \" chunks (012)";
+					return false;
+				}
+				if(fm->audio_block) {
+					if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
+					return false;
+				}
+				fm->format_block = fm->num_blocks;
+			}
+			else if(!memcmp(buffer, "data", 4)) { /* use first 4 bytes instead of whole GUID */
+				if(fm->audio_block) {
+					if(error) *error = "invalid Wave64 metadata: multiple \"data\" chunks (014)";
+					return false;
+				}
+				if(!fm->format_block) {
+					if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
+					return false;
+				}
+				fm->audio_block = fm->num_blocks;
+			}
+		}
+		else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
+			if(!memcmp(buffer, "COMM", 4)) {
+				if(fm->format_block) {
+					if(error) *error = "invalid AIFF metadata: multiple \"COMM\" chunks (016)";
+					return false;
+				}
+				if(fm->audio_block) {
+					if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
+					return false;
+				}
+				fm->format_block = fm->num_blocks;
+			}
+			else if(!memcmp(buffer, "SSND", 4)) {
+				if(fm->audio_block) {
+					if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (018)";
+					return false;
+				}
+				if(!fm->format_block) {
+					if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
+					return false;
+				}
+				fm->audio_block = fm->num_blocks;
+				/* read SSND offset size */
+				if(fread(buffer+4, 1, 8, f) != 8) {
+					if(error) *error = "read error (020)";
+					return false;
+				}
+				fm->ssnd_offset_size = unpack32be_(buffer+8);
+			}
+		}
+		else {
+			FLAC__ASSERT(0);
+			/* double protection: */
+			if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (021)";
+			return false;
+		}
+		if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
+			return false;
+	}
+	if(!type_found) {
+		if(error) *error = "no foreign metadata found (022)";
+		return false;
+	}
+	if(fm->is_rf64 && !ds64_found) {
+		if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)";
+		return false;
+	}
+	if(!fm->format_block) {
+		if(error)
+			*error =
+				fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (024)" :
+				fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"fmt \" chunk (025)" :
+				"invalid AIFF file: missing \"COMM\" chunk (026)";
+		return false;
+	}
+	if(!fm->audio_block) {
+		if(error)
+			*error =
+				fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (027)" :
+				fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"data\" chunk (028)" :
+				"invalid AIFF file: missing \"SSND\" chunk (029)";
+		return false;
+	}
+	return true;
+}
+
+static FLAC__bool write_to_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error)
+{
+	size_t i;
+	if(fseeko(fout, offset1, SEEK_SET) < 0) {
+		if(error) *error = "seek failed in WAVE/AIFF file (002)";
+		return false;
+	}
+	/* don't write first (RIFF/RF64/FORM) chunk, or ds64 chunk in the case of RF64 */
+	for(i = fm->is_rf64?2:1; i < fm->format_block; i++) {
+		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+			if(error) *error = "seek failed in FLAC file (003)";
+			return false;
+		}
+		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)"))
+			return false;
+	}
+	if(fseeko(fout, offset2, SEEK_SET) < 0) {
+		if(error) *error = "seek failed in WAVE/AIFF file (006)";
+		return false;
+	}
+	for(i = fm->format_block+1; i < fm->audio_block; i++) {
+		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+			if(error) *error = "seek failed in FLAC file (007)";
+			return false;
+		}
+		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)"))
+			return false;
+	}
+	if(fseeko(fout, offset3, SEEK_SET) < 0) {
+		if(error) *error = "seek failed in WAVE/AIFF file (010)";
+		return false;
+	}
+	for(i = fm->audio_block+1; i < fm->num_blocks; i++) {
+		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+			if(error) *error = "seek failed in FLAC file (011)";
+			return false;
+		}
+		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)"))
+			return false;
+	}
+	return true;
+}
+
+foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type)
+{
+	/* calloc() to zero all the member variables */
+	foreign_metadata_t *x = calloc(sizeof(foreign_metadata_t), 1);
+	if(x) {
+		x->type = type;
+		x->is_rf64 = false;
+	}
+	return x;
+}
+
+void flac__foreign_metadata_delete(foreign_metadata_t *fm)
+{
+	if(fm) {
+		if(fm->blocks)
+			free(fm->blocks);
+		free(fm);
+	}
+}
+
+FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error)
+{
+	FLAC__bool ok;
+	FILE *f = flac_fopen(filename, "rb");
+	if(!f) {
+		if(error) *error = "can't open AIFF file for reading (000)";
+		return false;
+	}
+	ok = read_from_aiff_(fm, f, error);
+	fclose(f);
+	return ok;
+}
+
+FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error)
+{
+	FLAC__bool ok;
+	FILE *f = flac_fopen(filename, "rb");
+	if(!f) {
+		if(error) *error = "can't open WAVE file for reading (000)";
+		return false;
+	}
+	ok = read_from_wave_(fm, f, error);
+	fclose(f);
+	return ok;
+}
+
+FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error)
+{
+	FLAC__bool ok;
+	FILE *f = flac_fopen(filename, "rb");
+	if(!f) {
+		if(error) *error = "can't open Wave64 file for reading (000)";
+		return false;
+	}
+	ok = read_from_wave64_(fm, f, error);
+	fclose(f);
+	return ok;
+}
+
+FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error)
+{
+	FLAC__bool ok;
+	FILE *fin, *fout;
+	FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
+	if(!it) {
+		if(error) *error = "out of memory (000)";
+		return false;
+	}
+	if(!FLAC__metadata_simple_iterator_init(it, outfilename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
+		if(error) *error = "can't initialize iterator (001)";
+		FLAC__metadata_simple_iterator_delete(it);
+		return false;
+	}
+	if(0 == (fin = flac_fopen(infilename, "rb"))) {
+		if(error) *error = "can't open WAVE/AIFF file for reading (002)";
+		FLAC__metadata_simple_iterator_delete(it);
+		return false;
+	}
+	if(0 == (fout = flac_fopen(outfilename, "r+b"))) {
+		if(error) *error = "can't open FLAC file for updating (003)";
+		FLAC__metadata_simple_iterator_delete(it);
+		fclose(fin);
+		return false;
+	}
+	ok = write_to_flac_(fm, fin, fout, it, error);
+	FLAC__metadata_simple_iterator_delete(it);
+	fclose(fin);
+	fclose(fout);
+	return ok;
+}
+
+FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error)
+{
+	FLAC__bool ok;
+	FILE *f;
+	FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
+	if(!it) {
+		if(error) *error = "out of memory (000)";
+		return false;
+	}
+	if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
+		if(error) *error = "can't initialize iterator (001)";
+		FLAC__metadata_simple_iterator_delete(it);
+		return false;
+	}
+	if(0 == (f = flac_fopen(filename, "rb"))) {
+		if(error) *error = "can't open FLAC file for reading (002)";
+		FLAC__metadata_simple_iterator_delete(it);
+		return false;
+	}
+	ok = read_from_flac_(fm, f, it, error);
+	FLAC__metadata_simple_iterator_delete(it);
+	fclose(f);
+	return ok;
+}
+
+FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error)
+{
+	FLAC__bool ok;
+	FILE *fin, *fout;
+	if(0 == (fin = flac_fopen(infilename, "rb"))) {
+		if(error) *error = "can't open FLAC file for reading (000)";
+		return false;
+	}
+	if(0 == (fout = flac_fopen(outfilename, "r+b"))) {
+		if(error) *error = "can't open WAVE/AIFF file for updating (001)";
+		fclose(fin);
+		return false;
+	}
+	ok = write_to_iff_(fm, fin, fout, offset1, offset2, offset3, error);
+	fclose(fin);
+	fclose(fout);
+	return ok;
+}
diff --git a/src/flac/foreign_metadata.h b/src/flac/foreign_metadata.h
new file mode 100644
index 0000000..e5a17dd
--- /dev/null
+++ b/src/flac/foreign_metadata.h
@@ -0,0 +1,74 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__foreign_metadata_h
+#define flac__foreign_metadata_h
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "utils.h"
+#include "share/compat.h"
+
+/* WATCHOUT: these enums are used to index internal arrays */
+typedef enum {
+	FOREIGN_BLOCK_TYPE__AIFF = 0, /* for AIFF and AIFF-C */
+	FOREIGN_BLOCK_TYPE__RIFF = 1, /* for WAVE and RF64 */
+	FOREIGN_BLOCK_TYPE__WAVE64 = 2  /* only for Sony's flavor */
+} foreign_block_type_t;
+
+typedef struct {
+	/* for encoding, this will be the offset in the WAVE/AIFF file of the chunk */
+	/* for decoding, this will be the offset in the FLAC file of the chunk data inside the APPLICATION block */
+	FLAC__off_t offset;
+	/* size is the actual size in bytes of the chunk to be stored/recreated. */
+	/* It includes the 8 bytes of chunk type and size, and any padding byte for alignment. */
+	/* For 'data'/'SSND' chunks, the size does not include the actual sound or padding bytes */
+	/* because these are not stored, they are recreated from the compressed FLAC stream. */
+	/* So for RIFF 'data', size is 8, and for AIFF 'SSND', size is 8 + 8 + ssnd_offset_size */
+	/* 32 bit size is OK because we only care about the non-sound data and FLAC metadata */
+	/* only supports a few megs anyway. */
+	FLAC__uint32 size;
+} foreign_block_t;
+
+typedef struct {
+	foreign_block_type_t type; /* currently we don't support multiple foreign types in a stream (and maybe never will) */
+	foreign_block_t *blocks;
+	size_t num_blocks;
+	size_t format_block; /* block number of 'fmt ' or 'COMM' chunk */
+	size_t audio_block; /* block number of 'data' or 'SSND' chunk */
+	FLAC__bool is_rf64; /* always false if type!=RIFF */
+	FLAC__uint32 ssnd_offset_size; /* 0 if type!=AIFF */
+} foreign_metadata_t;
+
+foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type);
+
+void flac__foreign_metadata_delete(foreign_metadata_t *fm);
+
+FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error);
+FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error);
+FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error);
+FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error);
+
+FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error);
+FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error);
+
+#endif
diff --git a/src/flac/iffscan.c b/src/flac/iffscan.c
new file mode 100644
index 0000000..8955465
--- /dev/null
+++ b/src/flac/iffscan.c
@@ -0,0 +1,129 @@
+/* iffscan - Simple AIFF/RIFF chunk scanner
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+#include "foreign_metadata.h"
+
+static FLAC__uint32 unpack32be_(const FLAC__byte *b)
+{
+	return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3];
+}
+
+static FLAC__uint32 unpack32le_(const FLAC__byte *b)
+{
+	return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24);
+}
+
+static FLAC__uint64 unpack64le_(const FLAC__byte *b)
+{
+	return (FLAC__uint64)b[0] + ((FLAC__uint64)b[1]<<8) + ((FLAC__uint64)b[2]<<16) + ((FLAC__uint64)b[3]<<24) + ((FLAC__uint64)b[4]<<32) + ((FLAC__uint64)b[5]<<40) + ((FLAC__uint64)b[6]<<48) + ((FLAC__uint64)b[7]<<56);
+}
+
+static FLAC__uint32 unpack32_(const FLAC__byte *b, foreign_block_type_t type)
+{
+	if(type == FOREIGN_BLOCK_TYPE__AIFF)
+		return unpack32be_(b);
+	else
+		return unpack32le_(b);
+}
+
+int main(int argc, char *argv[])
+{
+	FILE *f;
+	char buf[36];
+	foreign_metadata_t *fm;
+	const char *fn, *error;
+	size_t i;
+	FLAC__uint32 size;
+
+#ifdef _WIN32
+	if (get_utf8_argv(&argc, &argv) != 0) {
+		fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n");
+		return 1;
+	}
+#endif
+
+	if(argc != 2) {
+		flac_fprintf(stderr, "usage: %s { file.wav | file.aif }\n", argv[0]);
+		return 1;
+	}
+	fn = argv[1];
+	if(0 == (f = flac_fopen(fn, "rb")) || fread(buf, 1, 4, f) != 4) {
+		flac_fprintf(stderr, "ERROR opening %s for reading\n", fn);
+		return 1;
+	}
+	fclose(f);
+	if(0 == (fm = flac__foreign_metadata_new(memcmp(buf, "RIFF", 4) && memcmp(buf, "RF64", 4)? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) {
+		flac_fprintf(stderr, "ERROR: out of memory\n");
+		return 1;
+	}
+	if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
+		if(!flac__foreign_metadata_read_from_aiff(fm, fn, &error)) {
+			flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error);
+			return 1;
+		}
+	}
+	else {
+		if(!flac__foreign_metadata_read_from_wave(fm, fn, &error)) {
+			flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error);
+			return 1;
+		}
+	}
+	if(0 == (f = flac_fopen(fn, "rb"))) {
+		flac_fprintf(stderr, "ERROR opening %s for reading\n", fn);
+		return 1;
+	}
+	for(i = 0; i < fm->num_blocks; i++) {
+		if(fseeko(f, fm->blocks[i].offset, SEEK_SET) < 0) {
+			flac_fprintf(stderr, "ERROR seeking in %s\n", fn);
+			return 1;
+		}
+		if(fread(buf, 1, i==0?12:8, f) != (i==0?12:8)) {
+			flac_fprintf(stderr, "ERROR reading %s\n", fn);
+			return 1;
+		}
+		size = unpack32_((FLAC__byte*)buf+4, fm->type);
+		printf("block:[%c%c%c%c] size=%08x=(%10u)", buf[0], buf[1], buf[2], buf[3], size, size);
+		if(i == 0)
+			printf(" type:[%c%c%c%c]", buf[8], buf[9], buf[10], buf[11]);
+		else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && i == fm->audio_block)
+			printf(" offset size=%08x=(%10u)", fm->ssnd_offset_size, fm->ssnd_offset_size);
+		else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && i == 1 && !memcmp(buf, "ds64", 4)) {
+			if(fread(buf+8, 1, 36-8, f) != 36-8) {
+				flac_fprintf(stderr, "ERROR reading %s\n", fn);
+				return 1;
+			}
+			printf("\n    RIFF size=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+8), unpack64le_((FLAC__byte*)buf+8));
+			printf("\n    data size=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+16), unpack64le_((FLAC__byte*)buf+16));
+			printf("\n    sample count=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+24), unpack64le_((FLAC__byte*)buf+24));
+			printf("\n    table size=%08x=(%10u)", unpack32le_((FLAC__byte*)buf+32), unpack32le_((FLAC__byte*)buf+32));
+		}
+		printf("\n");
+	}
+	fclose(f);
+	flac__foreign_metadata_delete(fm);
+	return 0;
+}
diff --git a/src/flac/iffscan.vcproj b/src/flac/iffscan.vcproj
new file mode 100644
index 0000000..8c26750
--- /dev/null
+++ b/src/flac/iffscan.vcproj
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="iffscan"

+	ProjectGUID="{4cefbc94-c215-11db-8314-0800200c9a66}"

+	RootNamespace="iffscan"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)_iffscan"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)_iffscan"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-6E5FBE522BFB}"

+			>

+			<File

+				RelativePath=".\foreign_metadata.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2D32A752A2FF}"

+			>

+			<File

+				RelativePath=".\foreign_metadata.c"

+				>

+			</File>

+			<File

+				RelativePath=".\iffscan.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/flac/iffscan.vcxproj b/src/flac/iffscan.vcxproj
new file mode 100644
index 0000000..98b5076
--- /dev/null
+++ b/src/flac/iffscan.vcxproj
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc94-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>iffscan</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <IntDir>$(Configuration)_iffscan\</IntDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+    <IntDir>$(Platform)\$(Configuration)_iffscan\</IntDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <IntDir>$(Configuration)_iffscan\</IntDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+    <IntDir>$(Platform)\$(Configuration)_iffscan\</IntDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="foreign_metadata.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="foreign_metadata.c" />

+    <ClCompile Include="iffscan.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\win_utf8_io\win_utf8_io_static.vcxproj">

+      <Project>{4cefbe02-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/flac/iffscan.vcxproj.filters b/src/flac/iffscan.vcxproj.filters
new file mode 100644
index 0000000..0636239
--- /dev/null
+++ b/src/flac/iffscan.vcxproj.filters
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-6E5FBE522BFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2D32A752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="foreign_metadata.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="foreign_metadata.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="iffscan.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/flac/local_string_utils.c b/src/flac/local_string_utils.c
new file mode 100644
index 0000000..7e25233
--- /dev/null
+++ b/src/flac/local_string_utils.c
@@ -0,0 +1,109 @@
+/* flac - Command-line FLAC encoder/decoder
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include "utils.h"
+#include "local_string_utils.h"
+
+/*	$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+flac__strlcpy(char *dst, const char *src, size_t siz)
+{
+	register char *d = dst;
+	register const char *s = src;
+	register size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0 && --n != 0) {
+		do {
+			if ((*d++ = *s++) == 0)
+				break;
+		} while (--n != 0);
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';		/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}
+
+/*	$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+flac__strlcat(char *dst, const char *src, size_t siz)
+{
+	register char *d = dst;
+	register const char *s = src;
+	register size_t n = siz;
+	size_t dlen;
+
+	/* Find the end of dst and adjust bytes left but don't go past end */
+	while (n-- != 0 && *d != '\0')
+		d++;
+	dlen = d - dst;
+	n = siz - dlen;
+
+	if (n == 0)
+		return(dlen + strlen(s));
+	while (*s != '\0') {
+		if (n != 1) {
+			*d++ = *s;
+			n--;
+		}
+		s++;
+	}
+	*d = '\0';
+
+	return(dlen + (s - src));	/* count does not include NUL */
+}
diff --git a/src/flac/local_string_utils.h b/src/flac/local_string_utils.h
new file mode 100644
index 0000000..06f2d41
--- /dev/null
+++ b/src/flac/local_string_utils.h
@@ -0,0 +1,28 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__local_string_utils_h
+#define flac__local_string_utils_h
+
+#include <stdlib.h> /* for size_t */
+
+size_t flac__strlcpy(char *dst, const char *src, size_t siz);
+size_t flac__strlcat(char *dst, const char *src, size_t siz);
+
+#endif
diff --git a/src/flac/main.c b/src/flac/main.c
new file mode 100644
index 0000000..c6c5b89
--- /dev/null
+++ b/src/flac/main.c
@@ -0,0 +1,2278 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if !defined _MSC_VER && !defined __MINGW32__
+/* unlink is in stdio.h in VC++ */
+#include <unistd.h> /* for unlink() */
+#endif
+#include "FLAC/all.h"
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "share/safe_str.h"
+#include "analyze.h"
+#include "decode.h"
+#include "encode.h"
+#include "local_string_utils.h" /* for flac__strlcat() and flac__strlcpy() */
+#include "utils.h"
+#include "vorbiscomment.h"
+
+#if 0
+/*[JEC] was:#if HAVE_GETOPT_LONG*/
+/*[JEC] see flac/include/share/getopt.h as to why the change */
+#  include <getopt.h>
+#else
+#  include "share/getopt.h"
+#endif
+
+static int do_it(void);
+
+static FLAC__bool init_options(void);
+static int parse_options(int argc, char *argv[]);
+static int parse_option(int short_option, const char *long_option, const char *option_argument);
+static void free_options(void);
+static void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value);
+static void add_compression_setting_string(compression_setting_type_t type, const char *value);
+static void add_compression_setting_uint32_t(compression_setting_type_t type, uint32_t value);
+
+static int usage_error(const char *message, ...);
+static void short_usage(void);
+static void show_version(void);
+static void show_help(void);
+static void show_explain(void);
+static void format_mistake(const char *infilename, FileFormat wrong, FileFormat right);
+
+static int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file);
+static int decode_file(const char *infilename);
+
+static const char *get_encoded_outfilename(const char *infilename);
+static const char *get_decoded_outfilename(const char *infilename);
+static const char *get_outfilename(const char *infilename, const char *suffix);
+
+static void die(const char *message);
+static int conditional_fclose(FILE *f);
+static char *local_strdup(const char *source);
+
+/*
+ * share__getopt format struct; note that for long options with no
+ * short option equivalent we just set the 'val' field to 0.
+ */
+static struct share__option long_options_[] = {
+	/*
+	 * general options
+	 */
+	{ "help"                  , share__no_argument, 0, 'h' },
+	{ "explain"               , share__no_argument, 0, 'H' },
+	{ "version"               , share__no_argument, 0, 'v' },
+	{ "decode"                , share__no_argument, 0, 'd' },
+	{ "analyze"               , share__no_argument, 0, 'a' },
+	{ "test"                  , share__no_argument, 0, 't' },
+	{ "stdout"                , share__no_argument, 0, 'c' },
+	{ "silent"                , share__no_argument, 0, 's' },
+	{ "totally-silent"        , share__no_argument, 0, 0 },
+	{ "warnings-as-errors"    , share__no_argument, 0, 'w' },
+	{ "force"                 , share__no_argument, 0, 'f' },
+	{ "delete-input-file"     , share__no_argument, 0, 0 },
+	{ "preserve-modtime"      , share__no_argument, 0, 0 },
+	{ "keep-foreign-metadata" , share__no_argument, 0, 0 },
+	{ "output-prefix"         , share__required_argument, 0, 0 },
+	{ "output-name"           , share__required_argument, 0, 'o' },
+	{ "skip"                  , share__required_argument, 0, 0 },
+	{ "until"                 , share__required_argument, 0, 0 },
+	{ "channel-map"           , share__required_argument, 0, 0 }, /* undocumented */
+
+	/*
+	 * decoding options
+	 */
+	{ "decode-through-errors", share__no_argument, 0, 'F' },
+	{ "cue"                  , share__required_argument, 0, 0 },
+	{ "apply-replaygain-which-is-not-lossless", share__optional_argument, 0, 0 }, /* undocumented */
+
+	/*
+	 * encoding options
+	 */
+	{ "cuesheet"                  , share__required_argument, 0, 0 },
+	{ "no-cued-seekpoints"        , share__no_argument, 0, 0 },
+	{ "picture"                   , share__required_argument, 0, 0 },
+	{ "tag"                       , share__required_argument, 0, 'T' },
+	{ "tag-from-file"             , share__required_argument, 0, 0 },
+	{ "compression-level-0"       , share__no_argument, 0, '0' },
+	{ "compression-level-1"       , share__no_argument, 0, '1' },
+	{ "compression-level-2"       , share__no_argument, 0, '2' },
+	{ "compression-level-3"       , share__no_argument, 0, '3' },
+	{ "compression-level-4"       , share__no_argument, 0, '4' },
+	{ "compression-level-5"       , share__no_argument, 0, '5' },
+	{ "compression-level-6"       , share__no_argument, 0, '6' },
+	{ "compression-level-7"       , share__no_argument, 0, '7' },
+	{ "compression-level-8"       , share__no_argument, 0, '8' },
+	{ "compression-level-9"       , share__no_argument, 0, '9' },
+	{ "best"                      , share__no_argument, 0, '8' },
+	{ "fast"                      , share__no_argument, 0, '0' },
+	{ "verify"                    , share__no_argument, 0, 'V' },
+	{ "force-raw-format"          , share__no_argument, 0, 0 },
+	{ "force-aiff-format"         , share__no_argument, 0, 0 },
+	{ "force-rf64-format"         , share__no_argument, 0, 0 },
+	{ "force-wave64-format"       , share__no_argument, 0, 0 },
+	{ "lax"                       , share__no_argument, 0, 0 },
+	{ "replay-gain"               , share__no_argument, 0, 0 },
+	{ "ignore-chunk-sizes"        , share__no_argument, 0, 0 },
+	{ "sector-align"              , share__no_argument, 0, 0 }, /* DEPRECATED */
+	{ "seekpoint"                 , share__required_argument, 0, 'S' },
+	{ "padding"                   , share__required_argument, 0, 'P' },
+#if FLAC__HAS_OGG
+	{ "ogg"                       , share__no_argument, 0, 0 },
+	{ "serial-number"             , share__required_argument, 0, 0 },
+#endif
+	{ "blocksize"                 , share__required_argument, 0, 'b' },
+	{ "exhaustive-model-search"   , share__no_argument, 0, 'e' },
+	{ "max-lpc-order"             , share__required_argument, 0, 'l' },
+	{ "apodization"               , share__required_argument, 0, 'A' },
+	{ "mid-side"                  , share__no_argument, 0, 'm' },
+	{ "adaptive-mid-side"         , share__no_argument, 0, 'M' },
+	{ "qlp-coeff-precision-search", share__no_argument, 0, 'p' },
+	{ "qlp-coeff-precision"       , share__required_argument, 0, 'q' },
+	{ "rice-partition-order"      , share__required_argument, 0, 'r' },
+	{ "endian"                    , share__required_argument, 0, 0 },
+	{ "channels"                  , share__required_argument, 0, 0 },
+	{ "bps"                       , share__required_argument, 0, 0 },
+	{ "sample-rate"               , share__required_argument, 0, 0 },
+	{ "sign"                      , share__required_argument, 0, 0 },
+	{ "input-size"                , share__required_argument, 0, 0 },
+	{ "error-on-compression-fail" , share__no_argument, 0, 0 },
+
+	/*
+	 * analysis options
+	 */
+	{ "residual-gnuplot", share__no_argument, 0, 0 },
+	{ "residual-text", share__no_argument, 0, 0 },
+
+	/*
+	 * negatives
+	 */
+	{ "no-preserve-modtime"       , share__no_argument, 0, 0 },
+	{ "no-decode-through-errors"  , share__no_argument, 0, 0 },
+	{ "no-silent"                 , share__no_argument, 0, 0 },
+	{ "no-force"                  , share__no_argument, 0, 0 },
+	{ "no-seektable"              , share__no_argument, 0, 0 },
+	{ "no-delete-input-file"      , share__no_argument, 0, 0 },
+	{ "no-keep-foreign-metadata"  , share__no_argument, 0, 0 },
+	{ "no-replay-gain"            , share__no_argument, 0, 0 },
+	{ "no-ignore-chunk-sizes"     , share__no_argument, 0, 0 },
+	{ "no-sector-align"           , share__no_argument, 0, 0 }, /* DEPRECATED */
+	{ "no-utf8-convert"           , share__no_argument, 0, 0 },
+	{ "no-lax"                    , share__no_argument, 0, 0 },
+#if FLAC__HAS_OGG
+	{ "no-ogg"                    , share__no_argument, 0, 0 },
+#endif
+	{ "no-exhaustive-model-search", share__no_argument, 0, 0 },
+	{ "no-mid-side"               , share__no_argument, 0, 0 },
+	{ "no-adaptive-mid-side"      , share__no_argument, 0, 0 },
+	{ "no-qlp-coeff-prec-search"  , share__no_argument, 0, 0 },
+	{ "no-padding"                , share__no_argument, 0, 0 },
+	{ "no-verify"                 , share__no_argument, 0, 0 },
+	{ "no-warnings-as-errors"     , share__no_argument, 0, 0 },
+	{ "no-residual-gnuplot"       , share__no_argument, 0, 0 },
+	{ "no-residual-text"          , share__no_argument, 0, 0 },
+	{ "no-error-on-compression-fail", share__no_argument, 0, 0 },
+	/*
+	 * undocumented debugging options for the test suite
+	 */
+	{ "disable-constant-subframes", share__no_argument, 0, 0 },
+	{ "disable-fixed-subframes"   , share__no_argument, 0, 0 },
+	{ "disable-verbatim-subframes", share__no_argument, 0, 0 },
+	{ "no-md5-sum"                , share__no_argument, 0, 0 },
+
+	{0, 0, 0, 0}
+};
+
+
+/*
+ * global to hold command-line option values
+ */
+
+static struct {
+	FLAC__bool show_help;
+	FLAC__bool show_explain;
+	FLAC__bool show_version;
+	FLAC__bool mode_decode;
+	FLAC__bool verify;
+	FLAC__bool treat_warnings_as_errors;
+	FLAC__bool force_file_overwrite;
+	FLAC__bool continue_through_decode_errors;
+	replaygain_synthesis_spec_t replaygain_synthesis_spec;
+	FLAC__bool lax;
+	FLAC__bool test_only;
+	FLAC__bool analyze;
+	FLAC__bool use_ogg;
+	FLAC__bool has_serial_number; /* true iff --serial-number was used */
+	long serial_number; /* this is the Ogg serial number and is unused for native FLAC */
+	FLAC__bool force_to_stdout;
+	FLAC__bool force_raw_format;
+	FLAC__bool force_aiff_format;
+	FLAC__bool force_rf64_format;
+	FLAC__bool force_wave64_format;
+	FLAC__bool delete_input;
+	FLAC__bool preserve_modtime;
+	FLAC__bool keep_foreign_metadata;
+	FLAC__bool replay_gain;
+	FLAC__bool ignore_chunk_sizes;
+	FLAC__bool sector_align;
+	FLAC__bool utf8_convert; /* true by default, to convert tag strings from locale to utf-8, false if --no-utf8-convert used */
+	const char *cmdline_forced_outfilename;
+	const char *output_prefix;
+	analysis_options aopts;
+	int padding; /* -1 => no -P options were given, 0 => -P- was given, else -P value */
+	size_t num_compression_settings;
+	compression_setting_t compression_settings[64]; /* bad MAGIC NUMBER but buffer overflow is checked */
+	const char *skip_specification;
+	const char *until_specification;
+	const char *cue_specification;
+	int format_is_big_endian;
+	int format_is_unsigned_samples;
+	int format_channels;
+	int format_bps;
+	int format_sample_rate;
+	FLAC__off_t format_input_size;
+	char requested_seek_points[5000]; /* bad MAGIC NUMBER but buffer overflow is checked */
+	int num_requested_seek_points; /* -1 => no -S options were given, 0 => -S- was given */
+	const char *cuesheet_filename;
+	FLAC__bool cued_seekpoints;
+	FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */
+	FLAC__bool error_on_compression_fail;
+
+	uint32_t num_files;
+	char **filenames;
+
+	FLAC__StreamMetadata *vorbis_comment;
+	FLAC__StreamMetadata *pictures[64];
+	uint32_t num_pictures;
+
+	struct {
+		FLAC__bool disable_constant_subframes;
+		FLAC__bool disable_fixed_subframes;
+		FLAC__bool disable_verbatim_subframes;
+		FLAC__bool do_md5;
+	} debug;
+} option_values;
+
+
+/*
+ * miscellaneous globals
+ */
+
+static FLAC__int32 align_reservoir_0[588], align_reservoir_1[588]; /* for carrying over samples from --sector-align */ /* DEPRECATED */
+static FLAC__int32 *align_reservoir[2] = { align_reservoir_0, align_reservoir_1 };
+static uint32_t align_reservoir_samples = 0; /* 0 .. 587 */
+
+
+int main(int argc, char *argv[])
+{
+	int retval = 0;
+
+#ifdef __EMX__
+	_response(&argc, &argv);
+	_wildcard(&argc, &argv);
+#endif
+#ifdef _WIN32
+	if (get_utf8_argv(&argc, &argv) != 0) {
+		fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n");
+		return 1;
+	}
+#endif
+
+	srand((uint32_t)time(0));
+#ifdef _WIN32
+	{
+		const char *var;
+		var = getenv("LC_ALL");
+		if (!var)
+			var = getenv("LC_NUMERIC");
+		if (!var)
+			var = getenv("LANG");
+		if (!var || strcmp(var, "C") != 0)
+			setlocale(LC_ALL, "");
+	}
+#else
+	setlocale(LC_ALL, "");
+#endif
+	if(!init_options()) {
+		flac__utils_printf(stderr, 1, "ERROR: allocating memory\n");
+		retval = 1;
+	}
+	else {
+		if((retval = parse_options(argc, argv)) == 0)
+			retval = do_it();
+	}
+
+	free_options();
+
+	return retval;
+}
+
+int do_it(void)
+{
+	int retval = 0;
+
+	if(option_values.show_version) {
+		show_version();
+		return 0;
+	}
+	else if(option_values.show_explain) {
+		show_explain();
+		return 0;
+	}
+	else if(option_values.show_help) {
+		show_help();
+		return 0;
+	}
+	else {
+		if(option_values.num_files == 0) {
+			if(flac__utils_verbosity_ >= 1)
+				short_usage();
+			return 0;
+		}
+
+		/*
+		 * tweak options; validate the values
+		 */
+		if(!option_values.mode_decode) {
+			if(0 != option_values.cue_specification)
+				return usage_error("ERROR: --cue is not allowed in test mode\n");
+		}
+		else {
+			if(option_values.test_only) {
+				if(0 != option_values.skip_specification)
+					return usage_error("ERROR: --skip is not allowed in test mode\n");
+				if(0 != option_values.until_specification)
+					return usage_error("ERROR: --until is not allowed in test mode\n");
+				if(0 != option_values.cue_specification)
+					return usage_error("ERROR: --cue is not allowed in test mode\n");
+				if(0 != option_values.analyze)
+					return usage_error("ERROR: analysis mode (-a/--analyze) and test mode (-t/--test) cannot be used together\n");
+			}
+		}
+
+		if(0 != option_values.cue_specification && (0 != option_values.skip_specification || 0 != option_values.until_specification))
+			return usage_error("ERROR: --cue may not be combined with --skip or --until\n");
+
+		if(option_values.format_channels >= 0) {
+			if(option_values.format_channels == 0 || (uint32_t)option_values.format_channels > FLAC__MAX_CHANNELS)
+				return usage_error("ERROR: invalid number of channels '%u', must be > 0 and <= %u\n", option_values.format_channels, FLAC__MAX_CHANNELS);
+		}
+		if(option_values.format_bps >= 0) {
+			if(option_values.format_bps != 8 && option_values.format_bps != 16 && option_values.format_bps != 24)
+				return usage_error("ERROR: invalid bits per sample '%u' (must be 8/16/24)\n", option_values.format_bps);
+		}
+		if(option_values.format_sample_rate >= 0) {
+			if(!FLAC__format_sample_rate_is_valid(option_values.format_sample_rate))
+				return usage_error("ERROR: invalid sample rate '%u', must be > 0 and <= %u\n", option_values.format_sample_rate, FLAC__MAX_SAMPLE_RATE);
+		}
+		if((option_values.force_raw_format?1:0) + (option_values.force_aiff_format?1:0) + (option_values.force_rf64_format?1:0) + (option_values.force_wave64_format?1:0) > 1)
+			return usage_error("ERROR: only one of --force-raw-format/--force-aiff-format/--force-rf64-format/--force-wave64-format allowed\n");
+		if(option_values.mode_decode) {
+			if(!option_values.force_raw_format) {
+				if(option_values.format_is_big_endian >= 0)
+					return usage_error("ERROR: --endian only allowed with --force-raw-format\n");
+				if(option_values.format_is_unsigned_samples >= 0)
+					return usage_error("ERROR: --sign only allowed with --force-raw-format\n");
+			}
+			if(option_values.format_channels >= 0)
+				return usage_error("ERROR: --channels not allowed with --decode\n");
+			if(option_values.format_bps >= 0)
+				return usage_error("ERROR: --bps not allowed with --decode\n");
+			if(option_values.format_sample_rate >= 0)
+				return usage_error("ERROR: --sample-rate not allowed with --decode\n");
+		}
+
+		if(option_values.ignore_chunk_sizes) {
+			if(option_values.mode_decode)
+				return usage_error("ERROR: --ignore-chunk-sizes only allowed for encoding\n");
+			if(0 != option_values.sector_align)
+				return usage_error("ERROR: --ignore-chunk-sizes not allowed with --sector-align\n");
+			if(0 != option_values.until_specification)
+				return usage_error("ERROR: --ignore-chunk-sizes not allowed with --until\n");
+			if(0 != option_values.cue_specification)
+				return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cue\n");
+			if(0 != option_values.cuesheet_filename)
+				return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cuesheet\n");
+		}
+		if(option_values.sector_align) {
+			if(option_values.mode_decode)
+				return usage_error("ERROR: --sector-align only allowed for encoding\n");
+			if(0 != option_values.skip_specification)
+				return usage_error("ERROR: --sector-align not allowed with --skip\n");
+			if(0 != option_values.until_specification)
+				return usage_error("ERROR: --sector-align not allowed with --until\n");
+			if(0 != option_values.cue_specification)
+				return usage_error("ERROR: --sector-align not allowed with --cue\n");
+			if(option_values.format_channels >= 0 && option_values.format_channels != 2)
+				return usage_error("ERROR: --sector-align can only be done with stereo input\n");
+			if(option_values.format_bps >= 0 && option_values.format_bps != 16)
+				return usage_error("ERROR: --sector-align can only be done with 16-bit samples\n");
+			if(option_values.format_sample_rate >= 0 && option_values.format_sample_rate != 44100)
+				return usage_error("ERROR: --sector-align can only be done with a sample rate of 44100\n");
+		}
+		if(option_values.replay_gain) {
+			if(option_values.force_to_stdout)
+				return usage_error("ERROR: --replay-gain not allowed with -c/--stdout\n");
+			if(option_values.mode_decode)
+				return usage_error("ERROR: --replay-gain only allowed for encoding\n");
+			if(option_values.format_channels > 2)
+				return usage_error("ERROR: --replay-gain can only be done with mono/stereo input\n");
+			if(option_values.format_sample_rate >= 0 && !grabbag__replaygain_is_valid_sample_frequency(option_values.format_sample_rate))
+				return usage_error("ERROR: invalid sample rate used with --replay-gain\n");
+			if(
+				(option_values.padding >= 0 && option_values.padding < (int)GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED) ||
+				(option_values.padding < 0 && FLAC_ENCODE__DEFAULT_PADDING < (int)GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED)
+			) {
+				flac__utils_printf(stderr, 1, "NOTE: --replay-gain may leave a small PADDING block even with --no-padding\n");
+			}
+		}
+		if(option_values.num_files > 1 && option_values.cmdline_forced_outfilename) {
+			return usage_error("ERROR: -o/--output-name cannot be used with multiple files\n");
+		}
+		if(option_values.cmdline_forced_outfilename && option_values.output_prefix) {
+			return usage_error("ERROR: --output-prefix conflicts with -o/--output-name\n");
+		}
+		if(!option_values.mode_decode && 0 != option_values.cuesheet_filename && option_values.num_files > 1) {
+			return usage_error("ERROR: --cuesheet cannot be used when encoding multiple files\n");
+		}
+		if(option_values.keep_foreign_metadata) {
+			/* we're not going to try and support the re-creation of broken WAVE files */
+			if(option_values.ignore_chunk_sizes)
+				return usage_error("ERROR: using --keep-foreign-metadata cannot be used with --ignore-chunk-sizes\n");
+			if(option_values.test_only)
+				return usage_error("ERROR: --keep-foreign-metadata is not allowed in test mode\n");
+			if(option_values.analyze)
+				return usage_error("ERROR: --keep-foreign-metadata is not allowed in analyis mode\n");
+			flac__utils_printf(stderr, 1, "NOTE: --keep-foreign-metadata is a new feature; make sure to test the output file before deleting the original.\n");
+		}
+	}
+
+	flac__utils_printf(stderr, 2, "\n");
+	flac__utils_printf(stderr, 2, "flac %s\n", FLAC__VERSION_STRING);
+	flac__utils_printf(stderr, 2, "Copyright (C) 2000-2009  Josh Coalson, 2011-2016  Xiph.Org Foundation\n");
+	flac__utils_printf(stderr, 2, "flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are\n");
+	flac__utils_printf(stderr, 2, "welcome to redistribute it under certain conditions.  Type `flac' for details.\n\n");
+
+	if(option_values.mode_decode) {
+		FLAC__bool first = true;
+
+		if(option_values.num_files == 0) {
+			retval = decode_file("-");
+		}
+		else {
+			uint32_t i;
+			if(option_values.num_files > 1)
+				option_values.cmdline_forced_outfilename = 0;
+			for(i = 0, retval = 0; i < option_values.num_files; i++) {
+				if(0 == strcmp(option_values.filenames[i], "-") && !first)
+					continue;
+				retval |= decode_file(option_values.filenames[i]);
+				first = false;
+			}
+		}
+	}
+	else { /* encode */
+		FLAC__bool first = true;
+
+		if(option_values.ignore_chunk_sizes)
+			flac__utils_printf(stderr, 1, "INFO: Make sure you know what you're doing when using --ignore-chunk-sizes.\n      Improper use can cause flac to encode non-audio data as audio.\n");
+
+		if(option_values.num_files == 0) {
+			retval = encode_file("-", first, true);
+		}
+		else {
+			uint32_t i;
+			if(option_values.num_files > 1)
+				option_values.cmdline_forced_outfilename = 0;
+			for(i = 0, retval = 0; i < option_values.num_files; i++) {
+				if(0 == strcmp(option_values.filenames[i], "-") && !first)
+					continue;
+				retval |= encode_file(option_values.filenames[i], first, i == (option_values.num_files-1));
+				first = false;
+			}
+			if(option_values.replay_gain && retval == 0) {
+				float album_gain, album_peak;
+				grabbag__replaygain_get_album(&album_gain, &album_peak);
+				for(i = 0; i < option_values.num_files; i++) {
+					const char *error, *outfilename = get_encoded_outfilename(option_values.filenames[i]);
+					if(0 == outfilename) {
+						flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", option_values.filenames[i]);
+						return 1;
+					}
+					if(0 != (error = grabbag__replaygain_store_to_file_album(outfilename, album_gain, album_peak, option_values.preserve_modtime))) {
+						flac__utils_printf(stderr, 1, "%s: ERROR writing ReplayGain album tags (%s)\n", outfilename, error);
+						retval = 1;
+					}
+				}
+			}
+		}
+	}
+
+	return retval;
+}
+
+FLAC__bool init_options(void)
+{
+	option_values.show_help = false;
+	option_values.show_explain = false;
+	option_values.mode_decode = false;
+	option_values.verify = false;
+	option_values.treat_warnings_as_errors = false;
+	option_values.force_file_overwrite = false;
+	option_values.continue_through_decode_errors = false;
+	option_values.replaygain_synthesis_spec.apply = false;
+	option_values.replaygain_synthesis_spec.use_album_gain = true;
+	option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__HARD;
+	option_values.replaygain_synthesis_spec.noise_shaping = NOISE_SHAPING_LOW;
+	option_values.replaygain_synthesis_spec.preamp = 0.0;
+	option_values.lax = false;
+	option_values.test_only = false;
+	option_values.analyze = false;
+	option_values.use_ogg = false;
+	option_values.has_serial_number = false;
+	option_values.serial_number = 0;
+	option_values.force_to_stdout = false;
+	option_values.force_raw_format = false;
+	option_values.force_aiff_format = false;
+	option_values.force_rf64_format = false;
+	option_values.force_wave64_format = false;
+	option_values.delete_input = false;
+	option_values.preserve_modtime = true;
+	option_values.keep_foreign_metadata = false;
+	option_values.replay_gain = false;
+	option_values.ignore_chunk_sizes = false;
+	option_values.sector_align = false;
+	option_values.utf8_convert = true;
+	option_values.cmdline_forced_outfilename = 0;
+	option_values.output_prefix = 0;
+	option_values.aopts.do_residual_text = false;
+	option_values.aopts.do_residual_gnuplot = false;
+	option_values.padding = -1;
+	option_values.num_compression_settings = 1;
+	option_values.compression_settings[0].type = CST_COMPRESSION_LEVEL;
+	option_values.compression_settings[0].value.t_unsigned = 5;
+	option_values.skip_specification = 0;
+	option_values.until_specification = 0;
+	option_values.cue_specification = 0;
+	option_values.format_is_big_endian = -1;
+	option_values.format_is_unsigned_samples = -1;
+	option_values.format_channels = -1;
+	option_values.format_bps = -1;
+	option_values.format_sample_rate = -1;
+	option_values.format_input_size = (FLAC__off_t)(-1);
+	option_values.requested_seek_points[0] = '\0';
+	option_values.num_requested_seek_points = -1;
+	option_values.cuesheet_filename = 0;
+	option_values.cued_seekpoints = true;
+	option_values.channel_map_none = false;
+	option_values.error_on_compression_fail = false;
+
+	option_values.num_files = 0;
+	option_values.filenames = 0;
+
+	if(0 == (option_values.vorbis_comment = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)))
+		return false;
+	option_values.num_pictures = 0;
+
+	option_values.debug.disable_constant_subframes = false;
+	option_values.debug.disable_fixed_subframes = false;
+	option_values.debug.disable_verbatim_subframes = false;
+	option_values.debug.do_md5 = true;
+
+	return true;
+}
+
+int parse_options(int argc, char *argv[])
+{
+	int short_option;
+	int option_index = 1;
+	FLAC__bool had_error = false;
+	const char *short_opts = "0123456789aA:b:cdefFhHl:mMo:pP:q:r:sS:tT:vVw";
+
+	while ((short_option = share__getopt_long(argc, argv, short_opts, long_options_, &option_index)) != -1) {
+		switch (short_option) {
+			case 0: /* long option with no equivalent short option */
+				had_error |= (parse_option(short_option, long_options_[option_index].name, share__optarg) != 0);
+				break;
+			case '?':
+			case ':':
+				had_error = true;
+				break;
+			default: /* short option */
+				had_error |= (parse_option(short_option, 0, share__optarg) != 0);
+				break;
+		}
+	}
+
+	if(had_error) {
+		return 1;
+	}
+
+	FLAC__ASSERT(share__optind <= argc);
+
+	option_values.num_files = argc - share__optind;
+
+	if(option_values.num_files > 0) {
+		uint32_t i = 0;
+		if(0 == (option_values.filenames = malloc(sizeof(char*) * option_values.num_files)))
+			die("out of memory allocating space for file names list");
+		while(share__optind < argc)
+			option_values.filenames[i++] = local_strdup(argv[share__optind++]);
+	}
+
+	return 0;
+}
+
+int parse_option(int short_option, const char *long_option, const char *option_argument)
+{
+	const char *violation;
+
+	if(short_option == 0) {
+		FLAC__ASSERT(0 != long_option);
+		if(0 == strcmp(long_option, "totally-silent")) {
+			flac__utils_verbosity_ = 0;
+		}
+		else if(0 == strcmp(long_option, "delete-input-file")) {
+			option_values.delete_input = true;
+		}
+		else if(0 == strcmp(long_option, "preserve-modtime")) {
+			option_values.preserve_modtime = true;
+		}
+		else if(0 == strcmp(long_option, "keep-foreign-metadata")) {
+			option_values.keep_foreign_metadata = true;
+		}
+		else if(0 == strcmp(long_option, "output-prefix")) {
+			FLAC__ASSERT(0 != option_argument);
+			option_values.output_prefix = option_argument;
+		}
+		else if(0 == strcmp(long_option, "skip")) {
+			FLAC__ASSERT(0 != option_argument);
+			option_values.skip_specification = option_argument;
+		}
+		else if(0 == strcmp(long_option, "until")) {
+			FLAC__ASSERT(0 != option_argument);
+			option_values.until_specification = option_argument;
+		}
+		else if(0 == strcmp(long_option, "input-size")) {
+			FLAC__ASSERT(0 != option_argument);
+			{
+				char *end;
+				FLAC__int64 ix;
+				ix = strtoll(option_argument, &end, 10);
+				if(0 == strlen(option_argument) || *end)
+					return usage_error("ERROR: --%s must be a number\n", long_option);
+				option_values.format_input_size = (FLAC__off_t)ix;
+				if(option_values.format_input_size != ix) /* check if FLAC__off_t is smaller than long long */
+					return usage_error("ERROR: --%s too large; this build of flac does not support filesizes over 2GB\n", long_option);
+				if(option_values.format_input_size <= 0)
+					return usage_error("ERROR: --%s must be > 0\n", long_option);
+			}
+		}
+		else if(0 == strcmp(long_option, "cue")) {
+			FLAC__ASSERT(0 != option_argument);
+			option_values.cue_specification = option_argument;
+		}
+		else if(0 == strcmp(long_option, "apply-replaygain-which-is-not-lossless")) {
+			option_values.replaygain_synthesis_spec.apply = true;
+			if (0 != option_argument) {
+				char *p;
+				option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__NONE;
+				option_values.replaygain_synthesis_spec.noise_shaping = NOISE_SHAPING_NONE;
+				option_values.replaygain_synthesis_spec.preamp = strtod(option_argument, &p);
+				for ( ; *p; p++) {
+					if (*p == 'a')
+						option_values.replaygain_synthesis_spec.use_album_gain = true;
+					else if (*p == 't')
+						option_values.replaygain_synthesis_spec.use_album_gain = false;
+					else if (*p == 'l')
+						option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__PEAK;
+					else if (*p == 'L')
+						option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__HARD;
+					else if (*p == 'n' && p[1] >= '0' && p[1] <= '3') {
+						option_values.replaygain_synthesis_spec.noise_shaping = p[1] - '0';
+						p++;
+					}
+					else
+						return usage_error("ERROR: bad specification string \"%s\" for --%s\n", option_argument, long_option);
+				}
+			}
+		}
+		else if(0 == strcmp(long_option, "channel-map")) {
+			if (0 == option_argument || strcmp(option_argument, "none"))
+				return usage_error("ERROR: only --channel-map=none currently supported\n");
+			option_values.channel_map_none = true;
+		}
+		else if(0 == strcmp(long_option, "cuesheet")) {
+			FLAC__ASSERT(0 != option_argument);
+			option_values.cuesheet_filename = option_argument;
+		}
+		else if(0 == strcmp(long_option, "picture")) {
+			const uint32_t max_pictures = sizeof(option_values.pictures)/sizeof(option_values.pictures[0]);
+			FLAC__ASSERT(0 != option_argument);
+			if(option_values.num_pictures >= max_pictures)
+				return usage_error("ERROR: too many --picture arguments, only %u allowed\n", max_pictures);
+			if(0 == (option_values.pictures[option_values.num_pictures] = grabbag__picture_parse_specification(option_argument, &violation)))
+				return usage_error("ERROR: (--picture) %s\n", violation);
+			option_values.num_pictures++;
+		}
+		else if(0 == strcmp(long_option, "tag-from-file")) {
+			FLAC__ASSERT(0 != option_argument);
+			if(!flac__vorbiscomment_add(option_values.vorbis_comment, option_argument, /*value_from_file=*/true, /*raw=*/!option_values.utf8_convert, &violation))
+				return usage_error("ERROR: (--tag-from-file) %s\n", violation);
+		}
+		else if(0 == strcmp(long_option, "no-cued-seekpoints")) {
+			option_values.cued_seekpoints = false;
+		}
+		else if(0 == strcmp(long_option, "force-raw-format")) {
+			option_values.force_raw_format = true;
+		}
+		else if(0 == strcmp(long_option, "force-aiff-format")) {
+			option_values.force_aiff_format = true;
+		}
+		else if(0 == strcmp(long_option, "force-rf64-format")) {
+			option_values.force_rf64_format = true;
+		}
+		else if(0 == strcmp(long_option, "force-wave64-format")) {
+			option_values.force_wave64_format = true;
+		}
+		else if(0 == strcmp(long_option, "lax")) {
+			option_values.lax = true;
+		}
+		else if(0 == strcmp(long_option, "replay-gain")) {
+			option_values.replay_gain = true;
+		}
+		else if(0 == strcmp(long_option, "ignore-chunk-sizes")) {
+			option_values.ignore_chunk_sizes = true;
+		}
+		else if(0 == strcmp(long_option, "sector-align")) {
+			flac__utils_printf(stderr, 1, "WARNING: --sector-align is DEPRECATED and may not exist in future versions of flac.\n");
+			flac__utils_printf(stderr, 1, "         shntool provides similar functionality\n");
+			option_values.sector_align = true;
+		}
+#if FLAC__HAS_OGG
+		else if(0 == strcmp(long_option, "ogg")) {
+			option_values.use_ogg = true;
+		}
+		else if(0 == strcmp(long_option, "serial-number")) {
+			option_values.has_serial_number = true;
+			option_values.serial_number = atol(option_argument);
+		}
+#endif
+		else if(0 == strcmp(long_option, "endian")) {
+			FLAC__ASSERT(0 != option_argument);
+			if(0 == strncmp(option_argument, "big", strlen(option_argument)))
+				option_values.format_is_big_endian = true;
+			else if(0 == strncmp(option_argument, "little", strlen(option_argument)))
+				option_values.format_is_big_endian = false;
+			else
+				return usage_error("ERROR: argument to --endian must be \"big\" or \"little\"\n");
+		}
+		else if(0 == strcmp(long_option, "channels")) {
+			FLAC__ASSERT(0 != option_argument);
+			option_values.format_channels = atoi(option_argument);
+		}
+		else if(0 == strcmp(long_option, "bps")) {
+			FLAC__ASSERT(0 != option_argument);
+			option_values.format_bps = atoi(option_argument);
+		}
+		else if(0 == strcmp(long_option, "sample-rate")) {
+			FLAC__ASSERT(0 != option_argument);
+			option_values.format_sample_rate = atoi(option_argument);
+		}
+		else if(0 == strcmp(long_option, "sign")) {
+			FLAC__ASSERT(0 != option_argument);
+			if(0 == strncmp(option_argument, "signed", strlen(option_argument)))
+				option_values.format_is_unsigned_samples = false;
+			else if(0 == strncmp(option_argument, "unsigned", strlen(option_argument)))
+				option_values.format_is_unsigned_samples = true;
+			else
+				return usage_error("ERROR: argument to --sign must be \"signed\" or \"unsigned\"\n");
+		}
+		else if(0 == strcmp(long_option, "residual-gnuplot")) {
+			option_values.aopts.do_residual_gnuplot = true;
+		}
+		else if(0 == strcmp(long_option, "residual-text")) {
+			option_values.aopts.do_residual_text = true;
+		}
+		/*
+		 * negatives
+		 */
+		else if(0 == strcmp(long_option, "no-preserve-modtime")) {
+			option_values.preserve_modtime = false;
+		}
+		else if(0 == strcmp(long_option, "no-decode-through-errors")) {
+			option_values.continue_through_decode_errors = false;
+		}
+		else if(0 == strcmp(long_option, "no-silent")) {
+			flac__utils_verbosity_ = 2;
+		}
+		else if(0 == strcmp(long_option, "no-force")) {
+			option_values.force_file_overwrite = false;
+		}
+		else if(0 == strcmp(long_option, "no-seektable")) {
+			option_values.num_requested_seek_points = 0;
+			option_values.requested_seek_points[0] = '\0';
+		}
+		else if(0 == strcmp(long_option, "no-delete-input-file")) {
+			option_values.delete_input = false;
+		}
+		else if(0 == strcmp(long_option, "no-keep-foreign-metadata")) {
+			option_values.keep_foreign_metadata = false;
+		}
+		else if(0 == strcmp(long_option, "no-replay-gain")) {
+			option_values.replay_gain = false;
+		}
+		else if(0 == strcmp(long_option, "no-ignore-chunk-sizes")) {
+			option_values.ignore_chunk_sizes = false;
+		}
+		else if(0 == strcmp(long_option, "no-sector-align")) {
+			option_values.sector_align = false;
+		}
+		else if(0 == strcmp(long_option, "no-utf8-convert")) {
+			option_values.utf8_convert = false;
+		}
+		else if(0 == strcmp(long_option, "no-lax")) {
+			option_values.lax = false;
+		}
+#if FLAC__HAS_OGG
+		else if(0 == strcmp(long_option, "no-ogg")) {
+			option_values.use_ogg = false;
+		}
+#endif
+		else if(0 == strcmp(long_option, "no-exhaustive-model-search")) {
+			add_compression_setting_bool(CST_DO_EXHAUSTIVE_MODEL_SEARCH, false);
+		}
+		else if(0 == strcmp(long_option, "no-mid-side")) {
+			add_compression_setting_bool(CST_DO_MID_SIDE, false);
+			add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
+		}
+		else if(0 == strcmp(long_option, "no-adaptive-mid-side")) {
+			add_compression_setting_bool(CST_DO_MID_SIDE, false);
+			add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
+		}
+		else if(0 == strcmp(long_option, "no-qlp-coeff-prec-search")) {
+			add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, false);
+		}
+		else if(0 == strcmp(long_option, "no-padding")) {
+			option_values.padding = 0;
+		}
+		else if(0 == strcmp(long_option, "no-verify")) {
+			option_values.verify = false;
+		}
+		else if(0 == strcmp(long_option, "no-warnings-as-errors")) {
+			option_values.treat_warnings_as_errors = false;
+		}
+		else if(0 == strcmp(long_option, "no-residual-gnuplot")) {
+			option_values.aopts.do_residual_gnuplot = false;
+		}
+		else if(0 == strcmp(long_option, "no-residual-text")) {
+			option_values.aopts.do_residual_text = false;
+		}
+		else if(0 == strcmp(long_option, "disable-constant-subframes")) {
+			option_values.debug.disable_constant_subframes = true;
+		}
+		else if(0 == strcmp(long_option, "disable-fixed-subframes")) {
+			option_values.debug.disable_fixed_subframes = true;
+		}
+		else if(0 == strcmp(long_option, "disable-verbatim-subframes")) {
+			option_values.debug.disable_verbatim_subframes = true;
+		}
+		else if(0 == strcmp(long_option, "no-md5-sum")) {
+			option_values.debug.do_md5 = false;
+		}
+		else if(0 == strcmp(long_option, "no-error-on-compression-fail")) {
+			option_values.error_on_compression_fail = false;
+		}
+		else if(0 == strcmp(long_option, "error-on-compression-fail")) {
+			option_values.error_on_compression_fail = true;
+		}
+	}
+	else {
+		switch(short_option) {
+			case 'h':
+				option_values.show_help = true;
+				break;
+			case 'H':
+				option_values.show_explain = true;
+				break;
+			case 'v':
+				option_values.show_version = true;
+				break;
+			case 'd':
+				option_values.mode_decode = true;
+				break;
+			case 'a':
+				option_values.mode_decode = true;
+				option_values.analyze = true;
+				break;
+			case 't':
+				option_values.mode_decode = true;
+				option_values.test_only = true;
+				break;
+			case 'c':
+				option_values.force_to_stdout = true;
+				break;
+			case 's':
+				flac__utils_verbosity_ = 1;
+				break;
+			case 'f':
+				option_values.force_file_overwrite = true;
+				break;
+			case 'o':
+				FLAC__ASSERT(0 != option_argument);
+				option_values.cmdline_forced_outfilename = option_argument;
+				break;
+			case 'F':
+				option_values.continue_through_decode_errors = true;
+				break;
+			case 'T':
+				FLAC__ASSERT(0 != option_argument);
+				if(!flac__vorbiscomment_add(option_values.vorbis_comment, option_argument, /*value_from_file=*/false, /*raw=*/!option_values.utf8_convert, &violation))
+					return usage_error("ERROR: (-T/--tag) %s\n", violation);
+				break;
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+				add_compression_setting_uint32_t(CST_COMPRESSION_LEVEL, short_option-'0');
+				break;
+			case '9':
+				return usage_error("ERROR: compression level '9' is reserved\n");
+			case 'V':
+				option_values.verify = true;
+				break;
+			case 'w':
+				option_values.treat_warnings_as_errors = true;
+				break;
+			case 'S':
+				FLAC__ASSERT(0 != option_argument);
+				if(0 == strcmp(option_argument, "-")) {
+					option_values.num_requested_seek_points = 0;
+					option_values.requested_seek_points[0] = '\0';
+				}
+				else {
+					if(option_values.num_requested_seek_points < 0)
+						option_values.num_requested_seek_points = 0;
+					option_values.num_requested_seek_points++;
+					if(strlen(option_values.requested_seek_points)+strlen(option_argument)+2 >= sizeof(option_values.requested_seek_points)) {
+						return usage_error("ERROR: too many seekpoints requested\n");
+					}
+					else {
+						size_t len = strlen(option_values.requested_seek_points);
+						flac_snprintf(option_values.requested_seek_points+len, sizeof(option_values.requested_seek_points) - len, "%s;", option_argument);
+					}
+				}
+				break;
+			case 'P':
+				FLAC__ASSERT(0 != option_argument);
+				option_values.padding = atoi(option_argument);
+				if(option_values.padding < 0)
+					return usage_error("ERROR: argument to -%c must be >= 0; for no padding use -%c-\n", short_option, short_option);
+				break;
+			case 'b':
+				{
+					uint32_t i ;
+					FLAC__ASSERT(0 != option_argument);
+					i = atoi(option_argument);
+					if((i < (int)FLAC__MIN_BLOCK_SIZE || i > (int)FLAC__MAX_BLOCK_SIZE))
+						return usage_error("ERROR: invalid blocksize (-%c) '%d', must be >= %u and <= %u\n", short_option, i, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
+					add_compression_setting_uint32_t(CST_BLOCKSIZE, (uint32_t)i);
+				}
+				break;
+			case 'e':
+				add_compression_setting_bool(CST_DO_EXHAUSTIVE_MODEL_SEARCH, true);
+				break;
+			case 'E':
+				add_compression_setting_bool(CST_DO_ESCAPE_CODING, true);
+				break;
+			case 'l':
+				{
+					uint32_t i ;
+					FLAC__ASSERT(0 != option_argument);
+					i = atoi(option_argument);
+					if(i > FLAC__MAX_LPC_ORDER)
+						return usage_error("ERROR: invalid LPC order (-%c) '%d', must be >= %u and <= %u\n", short_option, i, 0, FLAC__MAX_LPC_ORDER);
+					add_compression_setting_uint32_t(CST_MAX_LPC_ORDER, i);
+				}
+				break;
+			case 'A':
+				FLAC__ASSERT(0 != option_argument);
+				add_compression_setting_string(CST_APODIZATION, option_argument);
+				break;
+			case 'm':
+				add_compression_setting_bool(CST_DO_MID_SIDE, true);
+				add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
+				break;
+			case 'M':
+				add_compression_setting_bool(CST_DO_MID_SIDE, true);
+				add_compression_setting_bool(CST_LOOSE_MID_SIDE, true);
+				break;
+			case 'p':
+				add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, true);
+				break;
+			case 'q':
+				{
+					uint32_t i ;
+					FLAC__ASSERT(0 != option_argument);
+					i = atoi(option_argument);
+					if((i > 0 && (i < FLAC__MIN_QLP_COEFF_PRECISION || i > FLAC__MAX_QLP_COEFF_PRECISION)))
+						return usage_error("ERROR: invalid value '%d' for qlp coeff precision (-%c), must be 0 or between %u and %u, inclusive\n", i, short_option, FLAC__MIN_QLP_COEFF_PRECISION, FLAC__MAX_QLP_COEFF_PRECISION);
+					add_compression_setting_uint32_t(CST_QLP_COEFF_PRECISION, i);
+				}
+				break;
+			case 'r':
+				{
+					uint32_t i;
+					char * p;
+					FLAC__ASSERT(0 != option_argument);
+					p = strchr(option_argument, ',');
+					if(0 == p) {
+						add_compression_setting_uint32_t(CST_MIN_RESIDUAL_PARTITION_ORDER, 0);
+						i = atoi(option_argument);
+						if(i > FLAC__MAX_RICE_PARTITION_ORDER)
+							return usage_error("ERROR: invalid value '%d' for residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+						add_compression_setting_uint32_t(CST_MAX_RESIDUAL_PARTITION_ORDER, i);
+					}
+					else {
+						i = atoi(option_argument);
+						if(i > FLAC__MAX_RICE_PARTITION_ORDER)
+							return usage_error("ERROR: invalid value '%d' for min residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+						add_compression_setting_uint32_t(CST_MIN_RESIDUAL_PARTITION_ORDER, i);
+						i = atoi(++p);
+						if(i > FLAC__MAX_RICE_PARTITION_ORDER)
+							return usage_error("ERROR: invalid value '%d' for max residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+						add_compression_setting_uint32_t(CST_MAX_RESIDUAL_PARTITION_ORDER, i);
+					}
+				}
+				break;
+			case 'R':
+				{
+					uint32_t i;
+					i = atoi(option_argument);
+					add_compression_setting_uint32_t(CST_RICE_PARAMETER_SEARCH_DIST, i);
+				}
+				break;
+			default:
+				FLAC__ASSERT(0);
+		}
+	}
+
+	return 0;
+}
+
+void free_options(void)
+{
+	uint32_t i;
+	if(0 != option_values.filenames) {
+		for(i = 0; i < option_values.num_files; i++) {
+			if(0 != option_values.filenames[i])
+				free(option_values.filenames[i]);
+		}
+		free(option_values.filenames);
+	}
+	if(0 != option_values.vorbis_comment)
+		FLAC__metadata_object_delete(option_values.vorbis_comment);
+	for(i = 0; i < option_values.num_pictures; i++)
+		FLAC__metadata_object_delete(option_values.pictures[i]);
+}
+
+void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value)
+{
+	if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+		die("too many compression settings");
+	option_values.compression_settings[option_values.num_compression_settings].type = type;
+	option_values.compression_settings[option_values.num_compression_settings].value.t_bool = value;
+	option_values.num_compression_settings++;
+}
+
+void add_compression_setting_string(compression_setting_type_t type, const char *value)
+{
+	if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+		die("too many compression settings");
+	option_values.compression_settings[option_values.num_compression_settings].type = type;
+	option_values.compression_settings[option_values.num_compression_settings].value.t_string = value;
+	option_values.num_compression_settings++;
+}
+
+void add_compression_setting_uint32_t(compression_setting_type_t type, uint32_t value)
+{
+	if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+		die("too many compression settings");
+	option_values.compression_settings[option_values.num_compression_settings].type = type;
+	option_values.compression_settings[option_values.num_compression_settings].value.t_unsigned = value;
+	option_values.num_compression_settings++;
+}
+
+int usage_error(const char *message, ...)
+{
+	if(flac__utils_verbosity_ >= 1) {
+		va_list args;
+
+		FLAC__ASSERT(0 != message);
+
+		va_start(args, message);
+
+		(void) vfprintf(stderr, message, args);
+
+		va_end(args);
+
+		printf("Type \"flac\" for a usage summary or \"flac --help\" for all options\n");
+	}
+
+	return 1;
+}
+
+void show_version(void)
+{
+	printf("flac %s\n", FLAC__VERSION_STRING);
+}
+
+static void usage_header(void)
+{
+	printf("===============================================================================\n");
+	printf("flac - Command-line FLAC encoder/decoder version %s\n", FLAC__VERSION_STRING);
+	printf("Copyright (C) 2000-2009  Josh Coalson\n");
+	printf("Copyright (C) 2011-2016  Xiph.Org Foundation\n");
+	printf("\n");
+	printf("This program is free software; you can redistribute it and/or\n");
+	printf("modify it under the terms of the GNU General Public License\n");
+	printf("as published by the Free Software Foundation; either version 2\n");
+	printf("of the License, or (at your option) any later version.\n");
+	printf("\n");
+	printf("This program is distributed in the hope that it will be useful,\n");
+	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
+	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
+	printf("GNU General Public License for more details.\n");
+	printf("\n");
+	printf("You should have received a copy of the GNU General Public License along\n");
+	printf("with this program; if not, write to the Free Software Foundation, Inc.,\n");
+	printf("51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n");
+	printf("===============================================================================\n");
+}
+
+static void usage_summary(void)
+{
+	printf("Usage:\n");
+	printf("\n");
+	printf(" Encoding: flac [<general-options>] [<encoding/format-options>] [INPUTFILE [...]]\n");
+	printf(" Decoding: flac -d [<general-options>] [<format-options>] [FLACFILE [...]]\n");
+	printf("  Testing: flac -t [<general-options>] [FLACFILE [...]]\n");
+	printf("Analyzing: flac -a [<general-options>] [<analysis-options>] [FLACFILE [...]]\n");
+	printf("\n");
+	printf("Be sure to read the list of known bugs at:\n");
+	printf("http://xiph.org/flac/documentation_bugs.html\n");
+	printf("\n");
+}
+
+void short_usage(void)
+{
+	usage_header();
+	printf("\n");
+	printf("This is the short help; for all options use 'flac --help'; for even more\n");
+	printf("instructions use 'flac --explain'\n");
+	printf("\n");
+	printf("Be sure to read the list of known bugs at:\n");
+	printf("http://xiph.org/flac/documentation_bugs.html\n");
+	printf("\n");
+	printf("To encode:\n");
+	printf("  flac [-#] [INPUTFILE [...]]\n");
+	printf("\n");
+	printf("  -# is -0 (fastest compression) to -8 (highest compression); -5 is the default\n");
+	printf("\n");
+	printf("To decode:\n");
+	printf("  flac -d [INPUTFILE [...]]\n");
+	printf("\n");
+	printf("To test:\n");
+	printf("  flac -t [INPUTFILE [...]]\n");
+}
+
+void show_help(void)
+{
+	usage_header();
+	usage_summary();
+	printf("general options:\n");
+	printf("  -v, --version                Show the flac version number\n");
+	printf("  -h, --help                   Show this screen\n");
+	printf("  -H, --explain                Show detailed explanation of usage and options\n");
+	printf("  -d, --decode                 Decode (the default behavior is to encode)\n");
+	printf("  -t, --test                   Same as -d except no decoded file is written\n");
+	printf("  -a, --analyze                Same as -d except an analysis file is written\n");
+	printf("  -c, --stdout                 Write output to stdout\n");
+	printf("  -s, --silent                 Do not write runtime encode/decode statistics\n");
+	printf("      --totally-silent         Do not print anything, including errors\n");
+	printf("      --no-utf8-convert        Do not convert tags from local charset to UTF-8\n");
+	printf("  -w, --warnings-as-errors     Treat all warnings as errors\n");
+	printf("  -f, --force                  Force overwriting of output files\n");
+	printf("  -o, --output-name=FILENAME   Force the output file name\n");
+	printf("      --output-prefix=STRING   Prepend STRING to output names\n");
+	printf("      --delete-input-file      Deletes after a successful encode/decode\n");
+	printf("      --preserve-modtime       Output files keep timestamp of input (default)\n");
+	printf("      --keep-foreign-metadata  Save/restore WAVE or AIFF non-audio chunks\n");
+	printf("      --skip={#|mm:ss.ss}      Skip the given initial samples for each input\n");
+	printf("      --until={#|[+|-]mm:ss.ss}  Stop at the given sample for each input file\n");
+#if FLAC__HAS_OGG
+	printf("      --ogg                    Use Ogg as transport layer\n");
+	printf("      --serial-number          Serial number to use for the FLAC stream\n");
+#endif
+	printf("analysis options:\n");
+	printf("      --residual-text          Include residual signal in text output\n");
+	printf("      --residual-gnuplot       Generate gnuplot files of residual distribution\n");
+	printf("decoding options:\n");
+	printf("  -F, --decode-through-errors  Continue decoding through stream errors\n");
+	printf("      --cue=[#.#][-[#.#]]      Set the beginning and ending cuepoints to decode\n");
+	printf("encoding options:\n");
+	printf("  -V, --verify                 Verify a correct encoding\n");
+	printf("      --lax                    Allow encoder to generate non-Subset files\n");
+	printf("      --ignore-chunk-sizes     Ignore data chunk sizes in WAVE/AIFF files\n");
+	printf("      --sector-align (DEPRECATED) Align multiple files on sector boundaries\n");
+	printf("      --replay-gain            Calculate ReplayGain & store in FLAC tags\n");
+	printf("      --cuesheet=FILENAME      Import cuesheet and store in CUESHEET block\n");
+	printf("      --picture=SPECIFICATION  Import picture and store in PICTURE block\n");
+	printf("  -T, --tag=FIELD=VALUE        Add a FLAC tag; may appear multiple times\n");
+	printf("      --tag-from-file=FIELD=FILENAME   Like --tag but gets value from file\n");
+	printf("  -S, --seekpoint={#|X|#x|#s}  Add seek point(s)\n");
+	printf("  -P, --padding=#              Write a PADDING block of length #\n");
+	printf("  -0, --compression-level-0, --fast  Synonymous with -l 0 -b 1152 -r 3\n");
+	printf("  -1, --compression-level-1          Synonymous with -l 0 -b 1152 -M -r 3\n");
+	printf("  -2, --compression-level-2          Synonymous with -l 0 -b 1152 -m -r 3\n");
+	printf("  -3, --compression-level-3          Synonymous with -l 6 -b 4096 -r 4\n");
+	printf("  -4, --compression-level-4          Synonymous with -l 8 -b 4096 -M -r 4\n");
+	printf("  -5, --compression-level-5          Synonymous with -l 8 -b 4096 -m -r 5\n");
+	printf("  -6, --compression-level-6          Synonymous with -l 8 -b 4096 -m -r 6\n");
+	printf("                                        -A tukey(0.5) -A partial_tukey(2)\n");
+	printf("  -7, --compression-level-7          Synonymous with -l 12 -b 4096 -m -r 6\n");
+	printf("                                         -A tukey(0.5) -A partial_tukey(2)\n");
+	printf("  -8, --compression-level-8, --best  Synonymous with -l 12 -b 4096 -m -r 6\n");
+	printf("                    -A tukey(0.5) -A partial_tukey(2) -A punchout_tukey(3)\n");
+	printf("  -b, --blocksize=#                  Specify blocksize in samples\n");
+	printf("  -m, --mid-side                     Try mid-side coding for each frame\n");
+	printf("  -M, --adaptive-mid-side            Adaptive mid-side coding for all frames\n");
+	printf("  -e, --exhaustive-model-search      Do exhaustive model search (expensive!)\n");
+	printf("  -A, --apodization=\"function\"       Window audio data with given the function\n");
+	printf("  -l, --max-lpc-order=#              Max LPC order; 0 => only fixed predictors\n");
+	printf("  -p, --qlp-coeff-precision-search   Exhaustively search LP coeff quantization\n");
+	printf("  -q, --qlp-coeff-precision=#        Specify precision in bits\n");
+	printf("  -r, --rice-partition-order=[#,]#   Set [min,]max residual partition order\n");
+	printf("format options:\n");
+	printf("      --force-raw-format       Treat input or output as raw samples\n");
+	printf("      --force-aiff-format      Force decoding to AIFF format\n");
+	printf("      --force-rf64-format      Force decoding to RF64 format\n");
+	printf("      --force-wave64-format    Force decoding to Wave64 format\n");
+	printf("raw format options:\n");
+	printf("      --endian={big|little}    Set byte order for samples\n");
+	printf("      --channels=#             Number of channels\n");
+	printf("      --bps=#                  Number of bits per sample\n");
+	printf("      --sample-rate=#          Sample rate in Hz\n");
+	printf("      --sign={signed|uint32_t} Sign of samples\n");
+	printf("      --input-size=#           Size of the raw input in bytes\n");
+	printf("negative options:\n");
+	printf("      --no-adaptive-mid-side\n");
+	printf("      --no-cued-seekpoints\n");
+	printf("      --no-decode-through-errors\n");
+	printf("      --no-delete-input-file\n");
+	printf("      --no-error-on-compression-fail\n");
+	printf("      --no-preserve-modtime\n");
+	printf("      --no-keep-foreign-metadata\n");
+	printf("      --no-exhaustive-model-search\n");
+	printf("      --no-lax\n");
+	printf("      --no-mid-side\n");
+#if FLAC__HAS_OGG
+	printf("      --no-ogg\n");
+#endif
+	printf("      --no-padding\n");
+	printf("      --no-qlp-coeff-prec-search\n");
+	printf("      --no-replay-gain\n");
+	printf("      --no-residual-gnuplot\n");
+	printf("      --no-residual-text\n");
+	printf("      --no-ignore-chunk-sizes\n");
+	printf("      --no-sector-align\n");
+	printf("      --no-seektable\n");
+	printf("      --no-silent\n");
+	printf("      --no-force\n");
+	printf("      --no-verify\n");
+	printf("      --no-warnings-as-errors\n");
+}
+
+void show_explain(void)
+{
+	usage_header();
+	usage_summary();
+	printf("For encoding:\n");
+	printf("  The input file(s) may be a PCM WAVE or RF64 file, AIFF (or uncompressed\n");
+	printf("  AIFF-C) file, or raw samples.\n");
+	printf("  The output file(s) will be in native FLAC or Ogg FLAC format\n");
+	printf("For decoding, the reverse is true.\n");
+	printf("\n");
+	printf("A single INPUTFILE may be - for stdin.  No INPUTFILE implies stdin.  Use of\n");
+	printf("stdin implies -c (write to stdout).  Normally you should use:\n");
+	printf("   flac [options] -o outfilename  or  flac -d [options] -o outfilename\n");
+	printf("instead of:\n");
+	printf("   flac [options] > outfilename   or  flac -d [options] > outfilename\n");
+	printf("since the former allows flac to seek backwards to write the STREAMINFO or\n");
+	printf("WAVE/AIFF header contents when necessary.\n");
+	printf("\n");
+	printf("flac checks for the presence of a AIFF/WAVE header to decide whether or not to\n");
+	printf("treat an input file as AIFF/WAVE format or raw samples.  If any input file is\n");
+	printf("raw you must specify the format options {-fb|fl} -fc -fp and -fs, which will\n");
+	printf("apply to all raw files.  You can force AIFF/WAVE files to be treated as raw\n");
+	printf("files using -fr.\n");
+	printf("\n");
+	printf("general options:\n");
+	printf("  -v, --version                Show the flac version number\n");
+	printf("  -h, --help                   Show basic usage a list of all options\n");
+	printf("  -H, --explain                Show this screen\n");
+	printf("  -d, --decode                 Decode (the default behavior is to encode)\n");
+	printf("  -t, --test                   Same as -d except no decoded file is written\n");
+	printf("  -a, --analyze                Same as -d except an analysis file is written\n");
+	printf("  -c, --stdout                 Write output to stdout\n");
+	printf("  -s, --silent                 Do not write runtime encode/decode statistics\n");
+	printf("      --totally-silent         Do not print anything of any kind, including\n");
+	printf("                               warnings or errors.  The exit code will be the\n");
+	printf("                               only way to determine successful completion.\n");
+	printf("      --no-utf8-convert        Do not convert tags from local charset to UTF-8.\n");
+	printf("                               This is useful for scripts, and setting tags in\n");
+	printf("                               situations where the locale is wrong.  This\n");
+	printf("                               option must appear before any tag options!\n");
+	printf("  -w, --warnings-as-errors     Treat all warnings as errors\n");
+	printf("  -f, --force                  Force overwriting of output files\n");
+	printf("  -o, --output-name=FILENAME   Force the output file name; usually flac just\n");
+	printf("                               changes the extension.  May only be used when\n");
+	printf("                               encoding a single file.  May not be used in\n");
+	printf("                               conjunction with --output-prefix.\n");
+	printf("      --output-prefix=STRING   Prefix each output file name with the given\n");
+	printf("                               STRING.  This can be useful for encoding or\n");
+	printf("                               decoding files to a different directory.  Make\n");
+	printf("                               sure if your STRING is a path name that it ends\n");
+	printf("                               with a '/' slash.\n");
+	printf("      --delete-input-file      Automatically delete the input file after a\n");
+	printf("                               successful encode or decode.  If there was an\n");
+	printf("                               error (including a verify error) the input file\n");
+	printf("                               is left intact.\n");
+	printf("      --preserve-modtime       Output files have their timestamps/permissions\n");
+	printf("                               set to match those of their inputs (this is\n");
+	printf("                               default).  Use --no-preserve-modtime to make\n");
+	printf("                               output files have the current time and default\n");
+	printf("                               permissions.\n");
+	printf("      --keep-foreign-metadata  If encoding, save WAVE or AIFF non-audio chunks\n");
+	printf("                               in FLAC metadata.  If decoding, restore any saved\n");
+	printf("                               non-audio chunks from FLAC metadata when writing\n");
+	printf("                               the decoded file.  Foreign metadata cannot be\n");
+	printf("                               transcoded, e.g. WAVE chunks saved in a FLAC file\n");
+	printf("                               cannot be restored when decoding to AIFF.  Input\n");
+	printf("                               and output must be regular files, not stdin/out.\n");
+	printf("      --skip={#|mm:ss.ss}      Skip the first # samples of each input file; can\n");
+	printf("                               be used both for encoding and decoding.  The\n");
+	printf("                               alternative form mm:ss.ss can be used to specify\n");
+	printf("                               minutes, seconds, and fractions of a second.\n");
+	printf("      --until={#|[+|-]mm:ss.ss}  Stop at the given sample number for each input\n");
+	printf("                               file.  The given sample number is not included\n");
+	printf("                               in the decoded output.  The alternative form\n");
+	printf("                               mm:ss.ss can be used to specify minutes,\n");
+	printf("                               seconds, and fractions of a second.  If a `+'\n");
+	printf("                               sign is at the beginning, the --until point is\n");
+	printf("                               relative to the --skip point.  If a `-' sign is\n");
+	printf("                               at the beginning, the --until point is relative\n");
+	printf("                               to end of the audio.\n");
+#if FLAC__HAS_OGG
+	printf("      --ogg                    When encoding, generate Ogg FLAC output instead\n");
+	printf("                               of native FLAC.  Ogg FLAC streams are FLAC\n");
+	printf("                               streams wrapped in an Ogg transport layer.  The\n");
+	printf("                               resulting file should have an '.oga' extension\n");
+	printf("                               and will still be decodable by flac.  When\n");
+	printf("                               decoding, force the input to be treated as\n");
+	printf("                               Ogg FLAC.  This is useful when piping input\n");
+	printf("                               from stdin or when the filename does not end in\n");
+	printf("                               '.oga' or '.ogg'.\n");
+	printf("      --serial-number          Serial number to use for the FLAC stream.  When\n");
+	printf("                               encoding and no serial number is given, flac\n");
+	printf("                               uses a random one.  If encoding to multiple files\n");
+	printf("                               the serial number is incremented for each file.\n");
+	printf("                               When decoding and no number is given, flac uses\n");
+	printf("                               the serial number of the first page.\n");
+#endif
+	printf("analysis options:\n");
+	printf("      --residual-text          Include residual signal in text output.  This\n");
+	printf("                               will make the file very big, much larger than\n");
+	printf("                               even the decoded file.\n");
+	printf("      --residual-gnuplot       Generate gnuplot files of residual distribution\n");
+	printf("                               of each subframe\n");
+	printf("decoding options:\n");
+	printf("  -F, --decode-through-errors  By default flac stops decoding with an error\n");
+	printf("                               and removes the partially decoded file if it\n");
+	printf("                               encounters a bitstream error.  With -F, errors\n");
+	printf("                               are still printed but flac will continue\n");
+	printf("                               decoding to completion.  Note that errors may\n");
+	printf("                               cause the decoded audio to be missing some\n");
+	printf("                               samples or have silent sections.\n");
+	printf("      --cue=[#.#][-[#.#]]      Set the beginning and ending cuepoints to\n");
+	printf("                               decode.  The optional first #.# is the track and\n");
+	printf("                               index point at which decoding will start; the\n");
+	printf("                               default is the beginning of the stream.  The\n");
+	printf("                               optional second #.# is the track and index point\n");
+	printf("                               at which decoding will end; the default is the\n");
+	printf("                               end of the stream.  If the cuepoint does not\n");
+	printf("                               exist, the closest one before it (for the start\n");
+	printf("                               point) or after it (for the end point) will be\n");
+	printf("                               used.  The cuepoints are merely translated into\n");
+	printf("                               sample numbers then used as --skip and --until.\n");
+	printf("                               A CD track can always be cued by, for example,\n");
+	printf("                               --cue=9.1-10.1 for track 9, even if the CD has\n");
+	printf("                               no 10th track.\n");
+	printf("encoding options:\n");
+	printf("  -V, --verify                 Verify a correct encoding by decoding the\n");
+	printf("                               output in parallel and comparing to the\n");
+	printf("                               original\n");
+	printf("      --lax                    Allow encoder to generate non-Subset files\n");
+	printf("      --ignore-chunk-sizes     Ignore data chunk sizes in WAVE/AIFF files;\n");
+	printf("                               useful when piping data from programs which\n");
+	printf("                               generate bogus data chunk sizes.\n");
+	printf("      --sector-align           Align encoding of multiple CD format WAVE files\n");
+	printf("                               on sector boundaries.  This option is DEPRECATED\n");
+	printf("                               and may not exist in future versions of flac.\n");
+	printf("                               shntool offers similar functionality.\n");
+	printf("      --replay-gain            Calculate ReplayGain values and store them as\n");
+	printf("                               FLAC tags.  Title gains/peaks will be computed\n");
+	printf("                               for each file, and an album gain/peak will be\n");
+	printf("                               computed for all files.  All input files must\n");
+	printf("                               have the same resolution, sample rate, and\n");
+	printf("                               number of channels.  The sample rate must be\n");
+	printf("                               one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1,\n");
+	printf("                               or 48 kHz.  NOTE: this option may also leave a\n");
+	printf("                               few extra bytes in the PADDING block.\n");
+	printf("      --cuesheet=FILENAME      Import the given cuesheet file and store it in\n");
+	printf("                               a CUESHEET metadata block.  This option may only\n");
+	printf("                               be used when encoding a single file.  A\n");
+	printf("                               seekpoint will be added for each index point in\n");
+	printf("                               the cuesheet to the SEEKTABLE unless\n");
+	printf("                               --no-cued-seekpoints is specified.\n");
+	printf("      --picture=SPECIFICATION  Import a picture and store it in a PICTURE block.\n");
+	printf("                               More than one --picture command can be specified.\n");
+	printf("                               The SPECIFICATION can either be a simple filename\n");
+	printf("                               for the picture file, or a complete specification\n");
+	printf("                               whose parts are separated by | characters.  Some\n");
+	printf("                               parts may be left empty to invoke default values.\n");
+	printf("                               Using a filename is shorthand for \"||||FILE\".\n");
+	printf("                               The SPECIFICATION format is:\n");
+	printf("         [TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE\n");
+	printf("           TYPE is optional; it is a number from one of:\n");
+	printf("              0: Other\n");
+	printf("              1: 32x32 pixels 'file icon' (PNG only)\n");
+	printf("              2: Other file icon\n");
+	printf("              3: Cover (front)\n");
+	printf("              4: Cover (back)\n");
+	printf("              5: Leaflet page\n");
+	printf("              6: Media (e.g. label side of CD)\n");
+	printf("              7: Lead artist/lead performer/soloist\n");
+	printf("              8: Artist/performer\n");
+	printf("              9: Conductor\n");
+	printf("             10: Band/Orchestra\n");
+	printf("             11: Composer\n");
+	printf("             12: Lyricist/text writer\n");
+	printf("             13: Recording Location\n");
+	printf("             14: During recording\n");
+	printf("             15: During performance\n");
+	printf("             16: Movie/video screen capture\n");
+	printf("             17: A bright coloured fish\n");
+	printf("             18: Illustration\n");
+	printf("             19: Band/artist logotype\n");
+	printf("             20: Publisher/Studio logotype\n");
+	printf("             The default is 3 (front cover).  There may only be one picture each\n");
+	printf("             of type 1 and 2 in a file.\n");
+	printf("           MIME-TYPE is optional; if left blank, it will be detected from the\n");
+	printf("             file.  For best compatibility with players, use pictures with MIME\n");
+	printf("             type image/jpeg or image/png.  The MIME type can also be --> to\n");
+	printf("             mean that FILE is actually a URL to an image, though this use is\n");
+	printf("             discouraged.\n");
+	printf("           DESCRIPTION is optional; the default is an empty string\n");
+	printf("           The next part specifies the resolution and color information.  If\n");
+	printf("             the MIME-TYPE is image/jpeg, image/png, or image/gif, you can\n");
+	printf("             usually leave this empty and they can be detected from the file.\n");
+	printf("             Otherwise, you must specify the width in pixels, height in pixels,\n");
+	printf("             and color depth in bits-per-pixel.  If the image has indexed colors\n");
+	printf("             you should also specify the number of colors used.\n");
+	printf("           FILE is the path to the picture file to be imported, or the URL if\n");
+	printf("             MIME type is -->\n");
+	printf("  -T, --tag=FIELD=VALUE        Add a FLAC tag.  Make sure to quote the\n");
+	printf("                               comment if necessary.  This option may appear\n");
+	printf("                               more than once to add several comments.  NOTE:\n");
+	printf("                               all tags will be added to all encoded files.\n");
+	printf("      --tag-from-file=FIELD=FILENAME   Like --tag, except FILENAME is a file\n");
+	printf("                               whose contents will be read verbatim to set the\n");
+	printf("                               tag value.  The contents will be converted to\n");
+	printf("                               UTF-8 from the local charset.  This can be used\n");
+	printf("                               to store a cuesheet in a tag (e.g.\n");
+	printf("                               --tag-from-file=\"CUESHEET=image.cue\").  Do not\n");
+	printf("                               try to store binary data in tag fields!  Use\n");
+	printf("                               APPLICATION blocks for that.\n");
+	printf("  -S, --seekpoint={#|X|#x|#s}  Include a point or points in a SEEKTABLE\n");
+	printf("       #  : a specific sample number for a seek point\n");
+	printf("       X  : a placeholder point (always goes at the end of the SEEKTABLE)\n");
+	printf("       #x : # evenly spaced seekpoints, the first being at sample 0\n");
+	printf("       #s : a seekpoint every # seconds; # does not have to be a whole number\n");
+	printf("     You may use many -S options; the resulting SEEKTABLE will be the unique-\n");
+	printf("           ified union of all such values.\n");
+	printf("     With no -S options, flac defaults to '-S 10s'.  Use -S- for no SEEKTABLE.\n");
+	printf("     Note: -S #x and -S #s will not work if the encoder can't determine the\n");
+	printf("           input size before starting.\n");
+	printf("     Note: if you use -S # and # is >= samples in the input, there will be\n");
+	printf("           either no seek point entered (if the input size is determinable\n");
+	printf("           before encoding starts) or a placeholder point (if input size is not\n");
+	printf("           determinable)\n");
+	printf("  -P, --padding=#              Tell the encoder to write a PADDING metadata\n");
+	printf("                               block of the given length (in bytes) after the\n");
+	printf("                               STREAMINFO block.  This is useful if you plan\n");
+	printf("                               to tag the file later with an APPLICATION\n");
+	printf("                               block; instead of having to rewrite the entire\n");
+	printf("                               file later just to insert your block, you can\n");
+	printf("                               write directly over the PADDING block.  Note\n");
+	printf("                               that the total length of the PADDING block will\n");
+	printf("                               be 4 bytes longer than the length given because\n");
+	printf("                               of the 4 metadata block header bytes.  You can\n");
+	printf("                               force no PADDING block at all to be written with\n");
+	printf("                               --no-padding.  The encoder writes a PADDING\n");
+	printf("                               block of 8192 bytes by default, or 65536 bytes\n");
+	printf("                               if the input audio is more than 20 minutes long.\n");
+	printf("  -b, --blocksize=#            Specify the blocksize in samples; the default is\n");
+	printf("                               1152 for -l 0, else 4096; must be one of 192,\n");
+	printf("                               576, 1152, 2304, 4608, 256, 512, 1024, 2048,\n");
+	printf("                               4096 (and 8192 or 16384 if the sample rate is\n");
+	printf("                               >48kHz) for Subset streams.\n");
+	printf("  -0, --compression-level-0, --fast  Synonymous with -l 0 -b 1152 -r 3\n");
+	printf("  -1, --compression-level-1          Synonymous with -l 0 -b 1152 -M -r 3\n");
+	printf("  -2, --compression-level-2          Synonymous with -l 0 -b 1152 -m -r 3\n");
+	printf("  -3, --compression-level-3          Synonymous with -l 6 -b 4096 -r 4\n");
+	printf("  -4, --compression-level-4          Synonymous with -l 8 -b 4096 -M -r 4\n");
+	printf("  -5, --compression-level-5          Synonymous with -l 8 -b 4096 -m -r 5\n");
+	printf("                                     -5 is the default setting\n");
+	printf("  -6, --compression-level-6          Synonymous with -l 8 -b 4096 -m -r 6\n");
+	printf("                                        -A tukey(0.5) -A partial_tukey(2)\n");
+	printf("  -7, --compression-level-7          Synonymous with -l 12 -b 4096 -m -r 6\n");
+	printf("                                         -A tukey(0.5) -A partial_tukey(2)\n");
+	printf("  -8, --compression-level-8, --best  Synonymous with -l 12 -b 4096 -m -r 6\n");
+	printf("                    -A tukey(0.5) -A partial_tukey(2) -A punchout_tukey(3)\n");
+	printf("  -m, --mid-side                     Try mid-side coding for each frame\n");
+	printf("                                     (stereo only)\n");
+	printf("  -M, --adaptive-mid-side            Adaptive mid-side coding for all frames\n");
+	printf("                                     (stereo only)\n");
+	printf("  -e, --exhaustive-model-search      Do exhaustive model search (expensive!)\n");
+	printf("  -A, --apodization=\"function\"       Window audio data with given the function.\n");
+	printf("                                     The functions are: bartlett, bartlett_hann,\n");
+	printf("                                     blackman, blackman_harris_4term_92db,\n");
+	printf("                                     connes, flattop, gauss(STDDEV), hamming,\n");
+	printf("                                     hann, kaiser_bessel, nuttall, rectangle,\n");
+	printf("                                     triangle, tukey(P), welch, partial_tukey(n),\n");
+	printf("                                     punchout_tukey(n). More than one may be\n");
+	printf("                                     specified but encoding time is a multiple of\n");
+	printf("                                     the number of functions since they are each\n");
+	printf("                                     tried in turn.  The encoder chooses suitable\n");
+	printf("                                     defaults in the absence of any -A options.\n");
+	printf("  -l, --max-lpc-order=#              Max LPC order; 0 => only fixed predictors.\n");
+	printf("                                     Must be <= 12 for Subset streams if sample\n");
+	printf("                                     rate is <=48kHz.\n");
+	printf("  -p, --qlp-coeff-precision-search   Do exhaustive search of LP coefficient\n");
+	printf("                                     quantization (expensive!); overrides -q;\n");
+	printf("                                     does nothing if using -l 0\n");
+	printf("  -q, --qlp-coeff-precision=#        Specify precision in bits of quantized\n");
+	printf("                                     linear-predictor coefficients; 0 => let\n");
+	printf("                                     encoder decide (the minimum is %u, the\n", FLAC__MIN_QLP_COEFF_PRECISION);
+	printf("                                     default is -q 0)\n");
+	printf("  -r, --rice-partition-order=[#,]#   Set [min,]max residual partition order\n");
+	printf("                                     (# is 0 to 15 inclusive; min defaults to 0;\n");
+	printf("                                     the default is -r 0; above 4 does not\n");
+	printf("                                     usually help much)\n");
+	printf("format options:\n");
+	printf("      --force-raw-format       Force input (when encoding) or output (when\n");
+	printf("                               decoding) to be treated as raw samples\n");
+	printf("      --force-aiff-format      Force the decoder to output AIFF format.  This\n");
+	printf("                               option is not needed if the output filename (as\n");
+	printf("                               set by -o) ends with .aif or .aiff; this option\n");
+	printf("                               has no effect when encoding since input AIFF is\n");
+	printf("                               auto-detected.\n");
+	printf("      --force-rf64-format      Force the decoder to output RF64 format.  This\n");
+	printf("                               option is not needed if the output filename (as\n");
+	printf("                               set by -o) ends with .rf64; this option\n");
+	printf("                               has no effect when encoding since input RF64 is\n");
+	printf("                               auto-detected.\n");
+	printf("      --force-wave64-format    Force the decoder to output Wave64 format.  This\n");
+	printf("                               option is not needed if the output filename (as\n");
+	printf("                               set by -o) ends with .w64; this option\n");
+	printf("                               has no effect when encoding since input Wave64 is\n");
+	printf("                               auto-detected.\n");
+	printf("raw format options:\n");
+	printf("      --endian={big|little}    Set byte order for samples\n");
+	printf("      --channels=#             Number of channels\n");
+	printf("      --bps=#                  Number of bits per sample\n");
+	printf("      --sample-rate=#          Sample rate in Hz\n");
+	printf("      --sign={signed|uint32_t} Sign of samples (the default is signed)\n");
+	printf("      --input-size=#           Size of the raw input in bytes.  If you are\n");
+	printf("                               encoding raw samples from stdin, you must set\n");
+	printf("                               this option in order to be able to use --skip,\n");
+	printf("                               --until, --cuesheet, or other options that need\n");
+	printf("                               to know the size of the input beforehand.  If\n");
+	printf("                               the size given is greater than what is found in\n");
+	printf("                               the input stream, the encoder will complain\n");
+	printf("                               about an unexpected end-of-file.  If the size\n");
+	printf("                               given is less, samples will be truncated.\n");
+	printf("negative options:\n");
+	printf("      --no-adaptive-mid-side\n");
+	printf("      --no-cued-seekpoints\n");
+	printf("      --no-decode-through-errors\n");
+	printf("      --no-delete-input-file\n");
+	printf("      --no-preserve-modtime\n");
+	printf("      --no-keep-foreign-metadata\n");
+	printf("      --no-exhaustive-model-search\n");
+	printf("      --no-lax\n");
+	printf("      --no-mid-side\n");
+#if FLAC__HAS_OGG
+	printf("      --no-ogg\n");
+#endif
+	printf("      --no-padding\n");
+	printf("      --no-qlp-coeff-prec-search\n");
+	printf("      --no-residual-gnuplot\n");
+	printf("      --no-residual-text\n");
+	printf("      --no-ignore-chunk-sizes\n");
+	printf("      --no-sector-align\n");
+	printf("      --no-seektable\n");
+	printf("      --no-silent\n");
+	printf("      --no-force\n");
+	printf("      --no-verify\n");
+	printf("      --no-warnings-as-errors\n");
+}
+
+void format_mistake(const char *infilename, FileFormat wrong, FileFormat right)
+{
+	/* WATCHOUT: indexed by FileFormat */
+	static const char * const ff[] = { " raw", " WAVE", "n RF64", "n AIFF", "n AIFF-C", " FLAC", "n Ogg FLAC" };
+	flac__utils_printf(stderr, 1, "WARNING: %s is not a%s file; treating as a%s file\n", infilename, ff[wrong], ff[right]);
+}
+
+int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file)
+{
+	FILE *encode_infile;
+	FLAC__byte lookahead[12];
+	uint32_t lookahead_length = 0;
+	FileFormat input_format = FORMAT_RAW;
+	int retval;
+	FLAC__off_t infilesize;
+	encode_options_t encode_options;
+	const char *outfilename = get_encoded_outfilename(infilename); /* the final name of the encoded file */
+	/* internal_outfilename is the file we will actually write to; it will be a temporary name if infilename==outfilename */
+	char *internal_outfilename = 0; /* NULL implies 'use outfilename' */
+	size_t infilename_length;
+
+	if(0 == outfilename) {
+		flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename);
+		return 1;
+	}
+
+	if(0 == strcmp(infilename, "-")) {
+		infilesize = (FLAC__off_t)(-1);
+		encode_infile = grabbag__file_get_binary_stdin();
+	}
+	else {
+		infilesize = grabbag__file_get_filesize(infilename);
+		if(0 == (encode_infile = flac_fopen(infilename, "rb"))) {
+			flac__utils_printf(stderr, 1, "ERROR: can't open input file %s: %s\n", infilename, strerror(errno));
+			return 1;
+		}
+	}
+
+	if(!option_values.force_raw_format) {
+		/* first set format based on name */
+		infilename_length = strlen(infilename);
+		if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".wav"))
+			input_format = FORMAT_WAVE;
+		else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".rf64"))
+			input_format = FORMAT_RF64;
+		else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".w64"))
+			input_format = FORMAT_WAVE64;
+		else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".aif"))
+			input_format = FORMAT_AIFF;
+		else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".aiff"))
+			input_format = FORMAT_AIFF;
+		else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".flac"))
+			input_format = FORMAT_FLAC;
+		else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".oga"))
+			input_format = FORMAT_OGGFLAC;
+		else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".ogg"))
+			input_format = FORMAT_OGGFLAC;
+
+		/* attempt to guess the file type based on the first 12 bytes */
+		if((lookahead_length = fread(lookahead, 1, 12, encode_infile)) < 12) {
+			/* all supported non-raw formats have at least 12 bytes of header to read */
+			if(input_format != FORMAT_RAW) {
+				format_mistake(infilename, input_format, FORMAT_RAW);
+				if(option_values.treat_warnings_as_errors) {
+					conditional_fclose(encode_infile);
+					return 1;
+				}
+			}
+			/* force to raw */
+			input_format = FORMAT_RAW;
+		}
+		else {
+			if(!memcmp(lookahead, "ID3", 3)) {
+				flac__utils_printf(stderr, 1, "ERROR: input file %s has an ID3v2 tag\n", infilename);
+				conditional_fclose(encode_infile);
+				return 1;
+			}
+			else if(!memcmp(lookahead, "RIFF", 4) && !memcmp(lookahead+8, "WAVE", 4))
+				input_format = FORMAT_WAVE;
+			else if(!memcmp(lookahead, "RF64", 4) && !memcmp(lookahead+8, "WAVE", 4))
+				input_format = FORMAT_RF64;
+			else if(!memcmp(lookahead, "riff\x2E\x91\xCF\x11\xA5\xD6\x28\xDB", 12)) /* just check 1st 12 bytes of GUID */
+				input_format = FORMAT_WAVE64;
+			else if(!memcmp(lookahead, "FORM", 4) && !memcmp(lookahead+8, "AIFF", 4))
+				input_format = FORMAT_AIFF;
+			else if(!memcmp(lookahead, "FORM", 4) && !memcmp(lookahead+8, "AIFC", 4))
+				input_format = FORMAT_AIFF_C;
+			else if(!memcmp(lookahead, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING)))
+				input_format = FORMAT_FLAC;
+			/*@@@ this could be made more accurate by looking at the first packet to make sure it's Ogg FLAC and not, say, Ogg Vorbis.  we do catch such problems later though. */
+			else if(!memcmp(lookahead, "OggS", 4))
+				input_format = FORMAT_OGGFLAC;
+			else {
+				/* didn't find header of any supported format */
+				if(input_format != FORMAT_RAW) {
+					format_mistake(infilename, input_format, FORMAT_RAW);
+					if(option_values.treat_warnings_as_errors) {
+						conditional_fclose(encode_infile);
+						return 1;
+					}
+				}
+				/* force to raw */
+				input_format = FORMAT_RAW;
+			}
+		}
+	}
+
+	if(option_values.keep_foreign_metadata) {
+		if(encode_infile == stdin || option_values.force_to_stdout) {
+			conditional_fclose(encode_infile);
+			return usage_error("ERROR: --keep-foreign-metadata cannot be used when encoding from stdin or to stdout\n");
+		}
+		if(input_format != FORMAT_WAVE && input_format != FORMAT_WAVE64 && input_format != FORMAT_RF64 && input_format != FORMAT_AIFF && input_format != FORMAT_AIFF_C) {
+			conditional_fclose(encode_infile);
+			return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE, Wave64, RF64, or AIFF input\n");
+		}
+	}
+
+	/*
+	 * Error if output file already exists (and -f not used).
+	 * Use grabbag__file_get_filesize() as a cheap way to check.
+	 */
+	if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (FLAC__off_t)(-1)) {
+		if(input_format == FORMAT_FLAC) {
+			/* need more detailed error message when re-flac'ing to avoid confusing the user */
+			flac__utils_printf(stderr, 1,
+				"ERROR: output file %s already exists.\n\n"
+				"By default flac encodes files to FLAC format; if you meant to decode this file\n"
+				"from FLAC to something else, use -d.  If you meant to re-encode this file from\n"
+				"FLAC to FLAC again, use -f to force writing to the same file, or -o to specify\n"
+				"a different output filename.\n",
+				outfilename
+			);
+		}
+		else if(input_format == FORMAT_OGGFLAC) {
+			/* need more detailed error message when re-flac'ing to avoid confusing the user */
+			flac__utils_printf(stderr, 1,
+				"ERROR: output file %s already exists.\n\n"
+				"By default 'flac -ogg' encodes files to Ogg FLAC format; if you meant to decode\n"
+				"this file from Ogg FLAC to something else, use -d.  If you meant to re-encode\n"
+				"this file from Ogg FLAC to Ogg FLAC again, use -f to force writing to the same\n"
+				"file, or -o to specify a different output filename.\n",
+				outfilename
+			);
+		}
+		else
+			flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename);
+		conditional_fclose(encode_infile);
+		return 1;
+	}
+
+	if(option_values.format_input_size >= 0) {
+	   	if (input_format != FORMAT_RAW || infilesize >= 0) {
+			flac__utils_printf(stderr, 1, "ERROR: can only use --input-size when encoding raw samples from stdin\n");
+			conditional_fclose(encode_infile);
+			return 1;
+		}
+		else {
+			infilesize = option_values.format_input_size;
+		}
+	}
+
+	if(option_values.sector_align && (input_format == FORMAT_FLAC || input_format == FORMAT_OGGFLAC)) {
+		flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input file is FLAC or Ogg FLAC\n");
+		conditional_fclose(encode_infile);
+		return 1;
+	}
+	if(option_values.sector_align && input_format == FORMAT_RAW && infilesize < 0) {
+		flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input size is unknown\n");
+		conditional_fclose(encode_infile);
+		return 1;
+	}
+
+	if(input_format == FORMAT_RAW) {
+		if(option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0 || option_values.format_channels < 0 || option_values.format_bps < 0 || option_values.format_sample_rate < 0) {
+			conditional_fclose(encode_infile);
+			return usage_error("ERROR: for encoding a raw file you must specify a value for --endian, --sign, --channels, --bps, and --sample-rate\n");
+		}
+	}
+	else {
+		if(option_values.format_is_big_endian >= 0 || option_values.format_is_unsigned_samples >= 0 || option_values.format_channels >= 0 || option_values.format_bps >= 0 || option_values.format_sample_rate >= 0) {
+			conditional_fclose(encode_infile);
+			return usage_error("ERROR: raw format options (--endian, --sign, --channels, --bps, and --sample-rate) are not allowed for non-raw input\n");
+		}
+	}
+
+	if(option_values.force_to_stdout) {
+		if(option_values.replay_gain) {
+			conditional_fclose(encode_infile);
+			return usage_error("ERROR: --replay-gain cannot be used when encoding to stdout\n");
+		}
+	}
+	if(option_values.replay_gain && option_values.use_ogg) {
+		conditional_fclose(encode_infile);
+		return usage_error("ERROR: --replay-gain cannot be used when encoding to Ogg FLAC yet\n");
+	}
+
+	if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &encode_options.skip_specification) || encode_options.skip_specification.is_relative) {
+		conditional_fclose(encode_infile);
+		return usage_error("ERROR: invalid value for --skip\n");
+	}
+
+	if(!flac__utils_parse_skip_until_specification(option_values.until_specification, &encode_options.until_specification)) { /*@@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */
+		conditional_fclose(encode_infile);
+		return usage_error("ERROR: invalid value for --until\n");
+	}
+	/* if there is no "--until" we want to default to "--until=-0" */
+	if(0 == option_values.until_specification)
+		encode_options.until_specification.is_relative = true;
+
+	encode_options.verify = option_values.verify;
+	encode_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors;
+#if FLAC__HAS_OGG
+	encode_options.use_ogg = option_values.use_ogg;
+	/* set a random serial number if one has not yet been specified */
+	if(!option_values.has_serial_number) {
+		option_values.serial_number = rand();
+		option_values.has_serial_number = true;
+	}
+	encode_options.serial_number = option_values.serial_number++;
+#endif
+	encode_options.lax = option_values.lax;
+	encode_options.padding = option_values.padding;
+	encode_options.num_compression_settings = option_values.num_compression_settings;
+	FLAC__ASSERT(sizeof(encode_options.compression_settings) >= sizeof(option_values.compression_settings));
+	memcpy(encode_options.compression_settings, option_values.compression_settings, sizeof(option_values.compression_settings));
+	encode_options.requested_seek_points = option_values.requested_seek_points;
+	encode_options.num_requested_seek_points = option_values.num_requested_seek_points;
+	encode_options.cuesheet_filename = option_values.cuesheet_filename;
+	encode_options.continue_through_decode_errors = option_values.continue_through_decode_errors;
+	encode_options.cued_seekpoints = option_values.cued_seekpoints;
+	encode_options.channel_map_none = option_values.channel_map_none;
+	encode_options.is_first_file = is_first_file;
+	encode_options.is_last_file = is_last_file;
+	encode_options.align_reservoir = align_reservoir;
+	encode_options.align_reservoir_samples = &align_reservoir_samples;
+	encode_options.replay_gain = option_values.replay_gain;
+	encode_options.ignore_chunk_sizes = option_values.ignore_chunk_sizes;
+	encode_options.sector_align = option_values.sector_align;
+	encode_options.vorbis_comment = option_values.vorbis_comment;
+	FLAC__ASSERT(sizeof(encode_options.pictures) >= sizeof(option_values.pictures));
+	memcpy(encode_options.pictures, option_values.pictures, sizeof(option_values.pictures));
+	encode_options.num_pictures = option_values.num_pictures;
+	encode_options.format = input_format;
+	encode_options.debug.disable_constant_subframes = option_values.debug.disable_constant_subframes;
+	encode_options.debug.disable_fixed_subframes = option_values.debug.disable_fixed_subframes;
+	encode_options.debug.disable_verbatim_subframes = option_values.debug.disable_verbatim_subframes;
+	encode_options.debug.do_md5 = option_values.debug.do_md5;
+	encode_options.error_on_compression_fail = option_values.error_on_compression_fail;
+
+	/* if infilename and outfilename point to the same file, we need to write to a temporary file */
+	if(encode_infile != stdin && grabbag__file_are_same(infilename, outfilename)) {
+		static const char *tmp_suffix = ".tmp,fl-ac+en'c";
+		size_t dest_len = strlen(outfilename) + strlen(tmp_suffix) + 1;
+		/*@@@@ still a remote possibility that a file with this filename exists */
+		if((internal_outfilename = safe_malloc_(dest_len)) == NULL) {
+			flac__utils_printf(stderr, 1, "ERROR allocating memory for tempfile name\n");
+			conditional_fclose(encode_infile);
+			return 1;
+		}
+		flac_snprintf(internal_outfilename, dest_len, "%s%s", outfilename, tmp_suffix);
+	}
+
+	if(input_format == FORMAT_RAW) {
+		encode_options.format_options.raw.is_big_endian = option_values.format_is_big_endian;
+		encode_options.format_options.raw.is_unsigned_samples = option_values.format_is_unsigned_samples;
+		encode_options.format_options.raw.channels = option_values.format_channels;
+		encode_options.format_options.raw.bps = option_values.format_bps;
+		encode_options.format_options.raw.sample_rate = option_values.format_sample_rate;
+
+		retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options);
+	}
+	else if(input_format == FORMAT_FLAC || input_format == FORMAT_OGGFLAC) {
+		retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options);
+	}
+	else if(input_format == FORMAT_WAVE || input_format == FORMAT_WAVE64 || input_format == FORMAT_RF64 || input_format == FORMAT_AIFF || input_format == FORMAT_AIFF_C) {
+		encode_options.format_options.iff.foreign_metadata = 0;
+
+		/* initialize foreign metadata if requested */
+		if(option_values.keep_foreign_metadata) {
+			encode_options.format_options.iff.foreign_metadata =
+				flac__foreign_metadata_new(
+					input_format==FORMAT_WAVE || input_format==FORMAT_RF64?
+						FOREIGN_BLOCK_TYPE__RIFF :
+					input_format==FORMAT_WAVE64?
+						FOREIGN_BLOCK_TYPE__WAVE64 :
+						FOREIGN_BLOCK_TYPE__AIFF
+				);
+			if(0 == encode_options.format_options.iff.foreign_metadata) {
+				flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n");
+				conditional_fclose(encode_infile);
+				if(internal_outfilename != 0)
+					free(internal_outfilename);
+				return 1;
+			}
+		}
+
+		retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options);
+
+		if(encode_options.format_options.iff.foreign_metadata)
+			flac__foreign_metadata_delete(encode_options.format_options.iff.foreign_metadata);
+	}
+	else {
+		FLAC__ASSERT(0);
+		retval = 1; /* double protection */
+	}
+
+	if(retval == 0) {
+		if(strcmp(outfilename, "-")) {
+			if(option_values.replay_gain) {
+				float title_gain, title_peak;
+				const char *error;
+				grabbag__replaygain_get_title(&title_gain, &title_peak);
+				if(
+					0 != (error = grabbag__replaygain_store_to_file_reference(internal_outfilename? internal_outfilename : outfilename, option_values.preserve_modtime)) ||
+					0 != (error = grabbag__replaygain_store_to_file_title(internal_outfilename? internal_outfilename : outfilename, title_gain, title_peak, option_values.preserve_modtime))
+				) {
+					flac__utils_printf(stderr, 1, "%s: ERROR writing ReplayGain reference/title tags (%s)\n", outfilename, error);
+					retval = 1;
+				}
+			}
+			if(option_values.preserve_modtime && strcmp(infilename, "-"))
+				grabbag__file_copy_metadata(infilename, internal_outfilename? internal_outfilename : outfilename);
+		}
+	}
+
+	/* rename temporary file if necessary */
+	if(retval == 0 && internal_outfilename != 0) {
+		if(flac_rename(internal_outfilename, outfilename) < 0) {
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+			/* on some flavors of windows, flac_rename() will fail if the destination already exists, so we unlink and try again */
+			if(flac_unlink(outfilename) < 0) {
+				flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, keeping both\n", internal_outfilename, outfilename);
+				retval = 1;
+			}
+			else if(flac_rename(internal_outfilename, outfilename) < 0) {
+				flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, you must do it\n", internal_outfilename, outfilename);
+				retval = 1;
+			}
+#else
+			flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, keeping both\n", internal_outfilename, outfilename);
+			retval = 1;
+#endif
+		}
+	}
+
+	/* handle --delete-input-file, but don't want to delete if piping from stdin, or if input filename and output filename are the same */
+	if(retval == 0 && option_values.delete_input && strcmp(infilename, "-") && internal_outfilename == 0)
+		flac_unlink(infilename);
+
+	if(internal_outfilename != 0)
+		free(internal_outfilename);
+
+	return retval;
+}
+
+int decode_file(const char *infilename)
+{
+	int retval;
+	FLAC__bool treat_as_ogg = false;
+	FileFormat output_format = FORMAT_WAVE;
+	decode_options_t decode_options;
+	const char *outfilename = get_decoded_outfilename(infilename);
+	size_t infilename_length;
+
+	if(0 == outfilename) {
+		flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename);
+		return 1;
+	}
+
+	/*
+	 * Error if output file already exists (and -f not used).
+	 * Use grabbag__file_get_filesize() as a cheap way to check.
+	 */
+	if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (FLAC__off_t)(-1)) {
+		flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename);
+		return 1;
+	}
+
+	if(option_values.force_raw_format)
+		output_format = FORMAT_RAW;
+	else if(
+		option_values.force_aiff_format ||
+		(strlen(outfilename) >= 4 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-4), ".aif")) ||
+		(strlen(outfilename) >= 5 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-5), ".aiff"))
+	)
+		output_format = FORMAT_AIFF;
+	else if(
+		option_values.force_rf64_format ||
+		(strlen(outfilename) >= 5 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-5), ".rf64"))
+	)
+		output_format = FORMAT_RF64;
+	else if(
+		option_values.force_wave64_format ||
+		(strlen(outfilename) >= 4 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-4), ".w64"))
+	)
+		output_format = FORMAT_WAVE64;
+	else
+		output_format = FORMAT_WAVE;
+
+	if(!option_values.test_only && !option_values.analyze) {
+		if(output_format == FORMAT_RAW && (option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0))
+			return usage_error("ERROR: for decoding to a raw file you must specify a value for --endian and --sign\n");
+	}
+
+	if(option_values.keep_foreign_metadata) {
+		if(0 == strcmp(infilename, "-") || 0 == strcmp(outfilename, "-"))
+			return usage_error("ERROR: --keep-foreign-metadata cannot be used when decoding from stdin or to stdout\n");
+		if(output_format != FORMAT_WAVE && output_format != FORMAT_WAVE64 && output_format != FORMAT_RF64 && output_format != FORMAT_AIFF && output_format != FORMAT_AIFF_C)
+			return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE, Wave64, RF64, or AIFF output\n");
+	}
+
+	infilename_length = strlen(infilename);
+	if(option_values.use_ogg)
+		treat_as_ogg = true;
+	else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".oga"))
+		treat_as_ogg = true;
+	else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".ogg"))
+		treat_as_ogg = true;
+	else
+		treat_as_ogg = false;
+
+#if !FLAC__HAS_OGG
+	if(treat_as_ogg) {
+		flac__utils_printf(stderr, 1, "%s: Ogg support has not been built into this copy of flac\n", infilename);
+		return 1;
+	}
+#endif
+
+	if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &decode_options.skip_specification) || decode_options.skip_specification.is_relative)
+		return usage_error("ERROR: invalid value for --skip\n");
+
+	if(!flac__utils_parse_skip_until_specification(option_values.until_specification, &decode_options.until_specification)) /*@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */
+		return usage_error("ERROR: invalid value for --until\n");
+	/* if there is no "--until" we want to default to "--until=-0" */
+	if(0 == option_values.until_specification)
+		decode_options.until_specification.is_relative = true;
+
+	if(option_values.cue_specification) {
+		if(!flac__utils_parse_cue_specification(option_values.cue_specification, &decode_options.cue_specification))
+			return usage_error("ERROR: invalid value for --cue\n");
+		decode_options.has_cue_specification = true;
+	}
+	else
+		decode_options.has_cue_specification = false;
+
+	decode_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors;
+	decode_options.continue_through_decode_errors = option_values.continue_through_decode_errors;
+	decode_options.replaygain_synthesis_spec = option_values.replaygain_synthesis_spec;
+#if FLAC__HAS_OGG
+	decode_options.is_ogg = treat_as_ogg;
+	decode_options.use_first_serial_number = !option_values.has_serial_number;
+	decode_options.serial_number = option_values.serial_number;
+#endif
+	decode_options.channel_map_none = option_values.channel_map_none;
+	decode_options.format = output_format;
+
+	if(output_format == FORMAT_RAW) {
+		decode_options.format_options.raw.is_big_endian = option_values.format_is_big_endian;
+		decode_options.format_options.raw.is_unsigned_samples = option_values.format_is_unsigned_samples;
+
+		retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options);
+	}
+	else {
+		decode_options.format_options.iff.foreign_metadata = 0;
+
+		/* initialize foreign metadata if requested */
+		if(option_values.keep_foreign_metadata) {
+			decode_options.format_options.iff.foreign_metadata =
+				flac__foreign_metadata_new(
+					output_format==FORMAT_WAVE || output_format==FORMAT_RF64?
+						FOREIGN_BLOCK_TYPE__RIFF :
+					output_format==FORMAT_WAVE64?
+						FOREIGN_BLOCK_TYPE__WAVE64 :
+						FOREIGN_BLOCK_TYPE__AIFF
+				);
+			if(0 == decode_options.format_options.iff.foreign_metadata) {
+				flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n");
+				return 1;
+			}
+		}
+
+		retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options);
+
+		if(decode_options.format_options.iff.foreign_metadata)
+			flac__foreign_metadata_delete(decode_options.format_options.iff.foreign_metadata);
+	}
+
+	if(retval == 0 && strcmp(infilename, "-")) {
+		if(option_values.preserve_modtime && strcmp(outfilename, "-"))
+			grabbag__file_copy_metadata(infilename, outfilename);
+		if(option_values.delete_input && !option_values.test_only && !option_values.analyze)
+			flac_unlink(infilename);
+	}
+
+	return retval;
+}
+
+const char *get_encoded_outfilename(const char *infilename)
+{
+	const char *suffix = (option_values.use_ogg? ".oga" : ".flac");
+	const char *p;
+
+	if(option_values.output_prefix) {
+		p = grabbag__file_get_basename(infilename);
+	}
+	else {
+		p = infilename;
+	}
+
+	return get_outfilename(p, suffix);
+}
+
+const char *get_decoded_outfilename(const char *infilename)
+{
+	const char *suffix;
+	const char *p;
+
+	if(option_values.output_prefix) {
+		p = grabbag__file_get_basename(infilename);
+	}
+	else {
+		p = infilename;
+	}
+
+	if(option_values.analyze) {
+		suffix = ".ana";
+	}
+	else if(option_values.force_raw_format) {
+		suffix = ".raw";
+	}
+	else if(option_values.force_aiff_format) {
+		suffix = ".aiff";
+	}
+	else if(option_values.force_rf64_format) {
+		suffix = ".rf64";
+	}
+	else if(option_values.force_wave64_format) {
+		suffix = ".w64";
+	}
+	else {
+		suffix = ".wav";
+	}
+	return get_outfilename(p, suffix);
+}
+
+const char *get_outfilename(const char *infilename, const char *suffix)
+{
+	if(0 == option_values.cmdline_forced_outfilename) {
+		static char buffer[4096];
+
+		if(0 == strcmp(infilename, "-") || option_values.force_to_stdout) {
+			buffer [0] = '-';
+			buffer [1] = 0;
+		}
+		else {
+			char *p;
+			if (flac__strlcpy(buffer, option_values.output_prefix? option_values.output_prefix : "", sizeof buffer) >= sizeof buffer)
+				return 0;
+			if (flac__strlcat(buffer, infilename, sizeof buffer) >= sizeof buffer)
+				return 0;
+			/* the . must come after any / to avoid problems with, e.g. "some.directory/extensionless-filename" */
+			if(0 == (p = strrchr(buffer, '.')) || strchr(p, '/')) {
+				if (flac__strlcat(buffer, suffix, sizeof buffer) >= sizeof buffer)
+					return 0;
+			}
+			else {
+				*p = '\0';
+				if (flac__strlcat(buffer, suffix, sizeof buffer) >= sizeof buffer)
+					return 0;
+			}
+		}
+		return buffer;
+	}
+	else
+		return option_values.cmdline_forced_outfilename;
+}
+
+void die(const char *message)
+{
+	FLAC__ASSERT(0 != message);
+	flac__utils_printf(stderr, 1, "ERROR: %s\n", message);
+	exit(1);
+}
+
+int conditional_fclose(FILE *f)
+{
+	if(f == 0 || f == stdin || f == stdout)
+		return 0;
+	else
+		return fclose(f);
+}
+
+char *local_strdup(const char *source)
+{
+	char *ret;
+	FLAC__ASSERT(0 != source);
+	if(0 == (ret = strdup(source)))
+		die("out of memory during strdup()");
+	return ret;
+}
diff --git a/src/flac/utils.c b/src/flac/utils.c
new file mode 100644
index 0000000..766d7e4
--- /dev/null
+++ b/src/flac/utils.c
@@ -0,0 +1,423 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/compat.h"
+#ifndef _WIN32
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE
+#endif
+#include <wchar.h>
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#endif
+
+const char *CHANNEL_MASK_TAG = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK";
+
+int flac__utils_verbosity_ = 2;
+
+static FLAC__bool local__parse_uint64_(const char *s, FLAC__uint64 *value)
+{
+	FLAC__uint64 ret = 0;
+	char c;
+
+	if(*s == '\0')
+		return false;
+
+	while('\0' != (c = *s++))
+		if(c >= '0' && c <= '9')
+			ret = ret * 10 + (c - '0');
+		else
+			return false;
+
+	*value = ret;
+	return true;
+}
+
+static FLAC__bool local__parse_timecode_(const char *s, double *value)
+{
+	double ret;
+	uint32_t i;
+	char c, *endptr;
+
+	/* parse [0-9][0-9]*: */
+	c = *s++;
+	if(c >= '0' && c <= '9')
+		i = (c - '0');
+	else
+		return false;
+	while(':' != (c = *s++)) {
+		if(c >= '0' && c <= '9')
+			i = i * 10 + (c - '0');
+		else
+			return false;
+	}
+	ret = (double)i * 60.;
+
+	/* parse [0-9]*[.,]?[0-9]* i.e. a sign-less rational number (. or , OK for fractional seconds, to support different locales) */
+	if(strspn(s, "1234567890.,") != strlen(s))
+		return false;
+	ret += strtod(s, &endptr);
+	if (endptr == s || *endptr)
+		return false;
+
+	*value = ret;
+	return true;
+}
+
+static FLAC__bool local__parse_cue_(const char *s, const char *end, uint32_t *track, uint32_t *indx)
+{
+	FLAC__bool got_track = false, got_index = false;
+	uint32_t t = 0, i = 0;
+	char c;
+
+	while(end? s < end : *s != '\0') {
+		c = *s++;
+		if(c >= '0' && c <= '9') {
+			t = t * 10 + (c - '0');
+			got_track = true;
+		}
+		else if(c == '.')
+			break;
+		else
+			return false;
+	}
+	while(end? s < end : *s != '\0') {
+		c = *s++;
+		if(c >= '0' && c <= '9') {
+			i = i * 10 + (c - '0');
+			got_index = true;
+		}
+		else
+			return false;
+	}
+	*track = t;
+	*indx = i;
+	return got_track && got_index;
+}
+
+/*
+ * this only works with sorted cuesheets (the spec strongly recommends but
+ * does not require sorted cuesheets).  but if it's not sorted, picking a
+ * nearest cue point has no significance.
+ */
+static FLAC__uint64 local__find_closest_cue_(const FLAC__StreamMetadata_CueSheet *cuesheet, uint32_t track, uint32_t indx, FLAC__uint64 total_samples, FLAC__bool look_forward)
+{
+	int t, i;
+	if(look_forward) {
+		for(t = 0; t < (int)cuesheet->num_tracks; t++)
+			for(i = 0; i < (int)cuesheet->tracks[t].num_indices; i++)
+				if(cuesheet->tracks[t].number > track || (cuesheet->tracks[t].number == track && cuesheet->tracks[t].indices[i].number >= indx))
+					return cuesheet->tracks[t].offset + cuesheet->tracks[t].indices[i].offset;
+		return total_samples;
+	}
+	else {
+		for(t = (int)cuesheet->num_tracks - 1; t >= 0; t--)
+			for(i = (int)cuesheet->tracks[t].num_indices - 1; i >= 0; i--)
+				if(cuesheet->tracks[t].number < track || (cuesheet->tracks[t].number == track && cuesheet->tracks[t].indices[i].number <= indx))
+					return cuesheet->tracks[t].offset + cuesheet->tracks[t].indices[i].offset;
+		return 0;
+	}
+}
+
+void flac__utils_printf(FILE *stream, int level, const char *format, ...)
+{
+	if(flac__utils_verbosity_ >= level) {
+		va_list args;
+
+		FLAC__ASSERT(0 != format);
+
+		va_start(args, format);
+
+		(void) flac_vfprintf(stream, format, args);
+
+		va_end(args);
+
+#ifdef _MSC_VER
+		if(stream == stderr)
+			fflush(stream); /* for some reason stderr is buffered in at least some if not all MSC libs */
+#endif
+	}
+}
+
+/* variables and functions for console status output */
+static FLAC__bool is_name_printed;
+static int stats_char_count = 0;
+static int console_width;
+static int console_chars_left;
+
+int get_console_width(void)
+{
+	int width = 0;
+#if defined _WIN32
+	width = win_get_console_width();
+#elif defined __EMX__
+	int s[2];
+	_scrsize (s);
+	width = s[0];
+#elif defined TIOCGWINSZ
+	struct winsize w;
+	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
+		width = w.ws_col;
+#endif
+	if (width <= 0)
+		width = 80;
+	return width;
+}
+
+size_t strlen_console(const char *text)
+{
+#ifdef _WIN32
+	return strlen_utf8(text);
+#elif defined(__DJGPP__) /* workaround for DJGPP missing wcswidth() */
+	return strlen(text);
+#else
+	size_t len;
+	wchar_t *wtmp;
+
+	len = strlen(text)+1;
+	wtmp = (wchar_t *)malloc(len*sizeof(wchar_t));
+	if (wtmp == NULL) return len-1;
+	mbstowcs(wtmp, text, len);
+	len = wcswidth(wtmp, len);
+	free(wtmp);
+
+	return len;
+#endif
+}
+
+void stats_new_file(void)
+{
+	is_name_printed = false;
+}
+
+void stats_clear(void)
+{
+	while (stats_char_count > 0 && stats_char_count--)
+		fprintf(stderr, "\b");
+}
+
+void stats_print_name(int level, const char *name)
+{
+	int len;
+
+	if (flac__utils_verbosity_ >= level) {
+		stats_clear();
+		if(is_name_printed) return;
+
+		console_width = get_console_width();
+		len = strlen_console(name)+2;
+		console_chars_left = console_width  - (len % console_width);
+		flac_fprintf(stderr, "%s: ", name);
+		is_name_printed = true;
+	}
+}
+
+void stats_print_info(int level, const char *format, ...)
+{
+	char tmp[80];
+	int len, clear_len;
+
+	if (flac__utils_verbosity_ >= level) {
+		va_list args;
+		va_start(args, format);
+		len = flac_vsnprintf(tmp, sizeof(tmp), format, args);
+		va_end(args);
+		stats_clear();
+		if (len >= console_chars_left) {
+			clear_len = console_chars_left;
+			while (clear_len > 0 && clear_len--) fprintf(stderr, " ");
+			fprintf(stderr, "\n");
+			console_chars_left = console_width;
+		}
+		stats_char_count = fprintf(stderr, "%s", tmp);
+		fflush(stderr);
+	}
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+size_t flac__utils_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;
+}
+#endif
+
+FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__SkipUntilSpecification *spec)
+{
+	FLAC__uint64 val;
+	FLAC__bool is_negative = false;
+
+	FLAC__ASSERT(0 != spec);
+
+	spec->is_relative = false;
+	spec->value_is_samples = true;
+	spec->value.samples = 0;
+
+	if(0 != s) {
+		if(s[0] == '-') {
+			is_negative = true;
+			spec->is_relative = true;
+			s++;
+		}
+		else if(s[0] == '+') {
+			spec->is_relative = true;
+			s++;
+		}
+
+		if(local__parse_uint64_(s, &val)) {
+			spec->value_is_samples = true;
+			spec->value.samples = (FLAC__int64)val;
+			if(is_negative)
+				spec->value.samples = -(spec->value.samples);
+		}
+		else {
+			double d;
+			if(!local__parse_timecode_(s, &d))
+				return false;
+			spec->value_is_samples = false;
+			spec->value.seconds = d;
+			if(is_negative)
+				spec->value.seconds = -(spec->value.seconds);
+		}
+	}
+
+	return true;
+}
+
+void flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, uint32_t sample_rate)
+{
+	FLAC__ASSERT(0 != spec);
+	if(!spec->value_is_samples) {
+		spec->value.samples = (FLAC__int64)(spec->value.seconds * (double)sample_rate);
+		spec->value_is_samples = true;
+	}
+}
+
+FLAC__bool flac__utils_parse_cue_specification(const char *s, utils__CueSpecification *spec)
+{
+	const char *start = s, *end = 0;
+
+	FLAC__ASSERT(0 != spec);
+
+	spec->has_start_point = spec->has_end_point = false;
+
+	s = strchr(s, '-');
+
+	if(0 != s) {
+		if(s == start)
+			start = 0;
+		end = s+1;
+		if(*end == '\0')
+			end = 0;
+	}
+
+	if(start) {
+		if(!local__parse_cue_(start, s, &spec->start_track, &spec->start_index))
+			return false;
+		spec->has_start_point = true;
+	}
+
+	if(end) {
+		if(!local__parse_cue_(end, 0, &spec->end_track, &spec->end_index))
+			return false;
+		spec->has_end_point = true;
+	}
+
+	return true;
+}
+
+void flac__utils_canonicalize_cue_specification(const utils__CueSpecification *cue_spec, const FLAC__StreamMetadata_CueSheet *cuesheet, FLAC__uint64 total_samples, utils__SkipUntilSpecification *skip_spec, utils__SkipUntilSpecification *until_spec)
+{
+	FLAC__ASSERT(0 != cue_spec);
+	FLAC__ASSERT(0 != cuesheet);
+	FLAC__ASSERT(0 != total_samples);
+	FLAC__ASSERT(0 != skip_spec);
+	FLAC__ASSERT(0 != until_spec);
+
+	skip_spec->is_relative = false;
+	skip_spec->value_is_samples = true;
+
+	until_spec->is_relative = false;
+	until_spec->value_is_samples = true;
+
+	if(cue_spec->has_start_point)
+		skip_spec->value.samples = local__find_closest_cue_(cuesheet, cue_spec->start_track, cue_spec->start_index, total_samples, /*look_forward=*/false);
+	else
+		skip_spec->value.samples = 0;
+
+	if(cue_spec->has_end_point)
+		until_spec->value.samples = local__find_closest_cue_(cuesheet, cue_spec->end_track, cue_spec->end_index, total_samples, /*look_forward=*/true);
+	else
+		until_spec->value.samples = total_samples;
+}
+
+FLAC__bool flac__utils_set_channel_mask_tag(FLAC__StreamMetadata *object, FLAC__uint32 channel_mask)
+{
+	FLAC__StreamMetadata_VorbisComment_Entry entry = { 0, 0 };
+	char tag[128];
+
+	FLAC__ASSERT(object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(strlen(CHANNEL_MASK_TAG)+1+2+16+1 <= sizeof(tag)); /* +1 for =, +2 for 0x, +16 for digits, +1 for NUL */
+	entry.entry = (FLAC__byte*)tag;
+	if((entry.length = flac_snprintf(tag, sizeof(tag), "%s=0x%04X", CHANNEL_MASK_TAG, (uint32_t)channel_mask)) >= sizeof(tag))
+		return false;
+	if(!FLAC__metadata_object_vorbiscomment_replace_comment(object, entry, /*all=*/true, /*copy=*/true))
+		return false;
+	return true;
+}
+
+FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask)
+{
+	int offset;
+	uint32_t val;
+	char *p;
+	FLAC__ASSERT(object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	if(0 > (offset = FLAC__metadata_object_vorbiscomment_find_entry_from(object, /*offset=*/0, CHANNEL_MASK_TAG)))
+		return false;
+	if(object->data.vorbis_comment.comments[offset].length < strlen(CHANNEL_MASK_TAG)+4)
+		return false;
+	if(0 == (p = strchr((const char *)object->data.vorbis_comment.comments[offset].entry, '='))) /* should never happen, but just in case */
+		return false;
+	if(FLAC__STRNCASECMP(p, "=0x", 3))
+		return false;
+	if(sscanf(p+3, "%x", &val) != 1)
+		return false;
+	*channel_mask = val;
+	return true;
+}
diff --git a/src/flac/utils.h b/src/flac/utils.h
new file mode 100644
index 0000000..36ceb37
--- /dev/null
+++ b/src/flac/utils.h
@@ -0,0 +1,73 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__utils_h
+#define flac__utils_h
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/ordinals.h"
+#include "FLAC/format.h" /* for FLAC__StreamMetadata_CueSheet */
+#include <stdio.h> /* for FILE */
+
+typedef enum { FORMAT_RAW, FORMAT_WAVE, FORMAT_WAVE64, FORMAT_RF64, FORMAT_AIFF, FORMAT_AIFF_C, FORMAT_FLAC, FORMAT_OGGFLAC } FileFormat;
+
+typedef struct {
+	FLAC__bool is_relative; /* i.e. specification string started with + or - */
+	FLAC__bool value_is_samples;
+	union {
+		double seconds;
+		FLAC__int64 samples;
+	} value;
+} utils__SkipUntilSpecification;
+
+typedef struct {
+	FLAC__bool has_start_point, has_end_point;
+	unsigned start_track, start_index;
+	unsigned end_track, end_index;
+} utils__CueSpecification;
+
+#ifdef FLAC__VALGRIND_TESTING
+size_t flac__utils_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
+#else
+#define flac__utils_fwrite fwrite
+#endif
+
+extern int flac__utils_verbosity_;
+void flac__utils_printf(FILE *stream, int level, const char *format, ...);
+
+int get_console_width(void);
+size_t strlen_console(const char *text);
+void stats_new_file(void);
+void stats_clear(void);
+void stats_print_name(int level, const char *name);
+void stats_print_info(int level, const char *format, ...);
+
+FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__SkipUntilSpecification *spec);
+void flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, uint32_t sample_rate);
+
+FLAC__bool flac__utils_parse_cue_specification(const char *s, utils__CueSpecification *spec);
+void flac__utils_canonicalize_cue_specification(const utils__CueSpecification *cue_spec, const FLAC__StreamMetadata_CueSheet *cuesheet, FLAC__uint64 total_samples, utils__SkipUntilSpecification *skip_spec, utils__SkipUntilSpecification *until_spec);
+
+FLAC__bool flac__utils_set_channel_mask_tag(FLAC__StreamMetadata *object, FLAC__uint32 channel_mask);
+FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask);
+
+#endif
diff --git a/src/flac/vorbiscomment.c b/src/flac/vorbiscomment.c
new file mode 100644
index 0000000..43de4cf
--- /dev/null
+++ b/src/flac/vorbiscomment.c
@@ -0,0 +1,254 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "vorbiscomment.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h" /* for grabbag__file_get_filesize() */
+#include "share/utf8.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+
+
+/*
+ * This struct and the following 4 static functions are copied from
+ * ../metaflac/.  Maybe someday there will be a convenience
+ * library for Vorbis comment parsing.
+ */
+typedef struct {
+	char *field; /* the whole field as passed on the command line, i.e. "NAME=VALUE" */
+	char *field_name;
+	/* according to the vorbis spec, field values can contain \0 so simple C strings are not enough here */
+	uint32_t field_value_length;
+	char *field_value;
+	FLAC__bool field_value_from_file; /* true if field_value holds a filename for the value, false for plain value */
+} Argument_VcField;
+
+static void die(const char *message)
+{
+	FLAC__ASSERT(0 != message);
+	fprintf(stderr, "ERROR: %s\n", message);
+	exit(1);
+}
+
+static char *local_strdup(const char *source)
+{
+	char *ret;
+	FLAC__ASSERT(0 != source);
+	if(0 == (ret = strdup(source)))
+		die("out of memory during strdup()");
+	return ret;
+}
+
+static FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, uint32_t *length, const char **violation)
+{
+	static const char * const violations[] = {
+		"field name contains invalid character",
+		"field contains no '=' character"
+	};
+
+	char *p, *q, *s;
+
+	if(0 != field)
+		*field = local_strdup(field_ref);
+
+	s = local_strdup(field_ref);
+
+	if(0 == (p = strchr(s, '='))) {
+		free(s);
+		*violation = violations[1];
+		return false;
+	}
+	*p++ = '\0';
+
+	for(q = s; *q; q++) {
+		if(*q < 0x20 || *q > 0x7d || *q == 0x3d) {
+			free(s);
+			*violation = violations[0];
+			return false;
+		}
+	}
+
+	*name = local_strdup(s);
+	*value = local_strdup(p);
+	*length = strlen(p);
+
+	free(s);
+	return true;
+}
+
+/* slight modification: no 'filename' arg, and errors are passed back in 'violation' instead of printed to stderr */
+static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw, const char **violation)
+{
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+	char *converted = NULL;
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(0 != field);
+	FLAC__ASSERT(0 != needs_write);
+
+	if(field->field_value_from_file) {
+		/* read the file into 'data' */
+		FILE *f = 0;
+		char *data = 0;
+		const FLAC__off_t size = grabbag__file_get_filesize(field->field_value);
+		if(size < 0) {
+			*violation = "can't open file for tag value";
+			return false;
+		}
+		if(size >= 0x100000) { /* magic arbitrary limit, actual format limit is near 16MB */
+			*violation = "file for tag value is too large";
+			return false;
+		}
+		if(0 == (data = malloc(size+1)))
+			die("out of memory allocating tag value");
+		data[size] = '\0';
+		if(0 == (f = flac_fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) {
+			free(data);
+			if(f)
+				fclose(f);
+			*violation = "error while reading file for tag value";
+			return false;
+		}
+		fclose(f);
+		if(strlen(data) != (size_t)size) {
+			free(data);
+			*violation = "file for tag value has embedded NULs";
+			return false;
+		}
+
+		/* move 'data' into 'converted', converting to UTF-8 if necessary */
+		if(raw) {
+			converted = data;
+		}
+		else if(utf8_encode(data, &converted) >= 0) {
+			free(data);
+		}
+		else {
+			free(data);
+			*violation = "error converting file contents to UTF-8 for tag value";
+			return false;
+		}
+
+		/* create and entry and append it */
+		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) {
+			free(converted);
+			*violation = "file for tag value is not valid UTF-8";
+			return false;
+		}
+		free(converted);
+		if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+			*violation = "memory allocation failure";
+			return false;
+		}
+
+		*needs_write = true;
+		return true;
+	}
+	else {
+		FLAC__bool needs_free = false;
+#ifdef _WIN32 /* everything in UTF-8 already. Must not alter */
+		entry.entry = (FLAC__byte *)field->field;
+#else
+		if(raw) {
+			entry.entry = (FLAC__byte *)field->field;
+		}
+		else if(utf8_encode(field->field, &converted) >= 0) {
+			entry.entry = (FLAC__byte *)converted;
+			needs_free = true;
+		}
+		else {
+			*violation = "error converting comment to UTF-8";
+			return false;
+		}
+#endif
+		entry.length = strlen((const char *)entry.entry);
+		if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) {
+			if(needs_free)
+				free(converted);
+			/*
+			 * our previous parsing has already established that the field
+			 * name is OK, so it must be the field value
+			 */
+			*violation = "tag value is not valid UTF-8";
+			return false;
+		}
+
+		if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+			if(needs_free)
+				free(converted);
+			*violation = "memory allocation failure";
+			return false;
+		}
+
+		*needs_write = true;
+		if(needs_free)
+			free(converted);
+		return true;
+	}
+}
+
+/*
+ * The rest of the code is novel
+ */
+
+static void free_field(Argument_VcField *obj)
+{
+	if(0 != obj->field)
+		free(obj->field);
+	if(0 != obj->field_name)
+		free(obj->field_name);
+	if(0 != obj->field_value)
+		free(obj->field_value);
+}
+
+FLAC__bool flac__vorbiscomment_add(FLAC__StreamMetadata *block, const char *comment, FLAC__bool value_from_file, FLAC__bool raw, const char **violation)
+{
+	Argument_VcField parsed;
+	FLAC__bool dummy;
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(0 != comment);
+
+	memset(&parsed, 0, sizeof(parsed));
+
+	parsed.field_value_from_file = value_from_file;
+	if(!parse_vorbis_comment_field(comment, &(parsed.field), &(parsed.field_name), &(parsed.field_value), &(parsed.field_value_length), violation)) {
+		free_field(&parsed);
+		return false;
+	}
+
+	if(parsed.field_value_length > 0 && !set_vc_field(block, &parsed, &dummy, raw, violation)) {
+		free_field(&parsed);
+		return false;
+	}
+	else {
+		free_field(&parsed);
+		return true;
+	}
+}
diff --git a/src/flac/vorbiscomment.h b/src/flac/vorbiscomment.h
new file mode 100644
index 0000000..ab6d738
--- /dev/null
+++ b/src/flac/vorbiscomment.h
@@ -0,0 +1,27 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__vorbiscomment_h
+#define flac__vorbiscomment_h
+
+#include "FLAC/metadata.h"
+
+FLAC__bool flac__vorbiscomment_add(FLAC__StreamMetadata *block, const char *comment, FLAC__bool value_from_file, FLAC__bool raw, const char **violation);
+
+#endif
diff --git a/src/libFLAC++/CMakeLists.txt b/src/libFLAC++/CMakeLists.txt
new file mode 100644
index 0000000..ec27835
--- /dev/null
+++ b/src/libFLAC++/CMakeLists.txt
@@ -0,0 +1,53 @@
+check_cxx_source_compiles("
+    #ifdef __STDC_NO_VLA__
+    syntax error;
+    #else
+    int fvla (int m, int * c)
+    {
+      int D[m];
+      return D[0] == c[0];
+    }
+
+    int main(int, char * []) { return 0; }
+    #endif"
+    HAVE_CXX_VARARRAYS)
+
+add_library(FLAC++
+    metadata.cpp
+    stream_decoder.cpp
+    stream_encoder.cpp)
+target_compile_definitions(FLAC++
+    PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:FLACPP_API_EXPORTS>
+    PUBLIC $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:FLAC__NO_DLL>)
+if(NOT WIN32)
+    target_compile_definitions(FLAC++ PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:FLAC__USE_VISIBILITY_ATTR>)
+endif()
+target_include_directories(FLAC++ INTERFACE
+    "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
+    "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
+target_link_libraries(FLAC++ PUBLIC FLAC)
+if(BUILD_SHARED_LIBS)
+    set_target_properties(FLAC++ PROPERTIES
+        VERSION 6.3.0
+        SOVERSION 6)
+    if(NOT WIN32)
+        set_target_properties(FLAC++ PROPERTIES CXX_VISIBILITY_PRESET hidden)
+    endif()
+endif()
+
+add_library(FLAC::FLAC++ ALIAS FLAC++)
+
+install(TARGETS FLAC++ EXPORT targets
+    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
+    LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
+    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/")
+
+if(INSTALL_PKGCONFIG_MODULES)
+    set(prefix "${CMAKE_INSTALL_PREFIX}")
+    set(exec_prefix "${CMAKE_INSTALL_PREFIX}")
+    set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}")
+    set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
+    configure_file(flac++.pc.in flac++.pc @ONLY)
+    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/flac++.pc"
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+endif()
diff --git a/src/libFLAC++/Makefile.am b/src/libFLAC++/Makefile.am
new file mode 100644
index 0000000..4a6919e
--- /dev/null
+++ b/src/libFLAC++/Makefile.am
@@ -0,0 +1,64 @@
+#  libFLAC++ - Free Lossless Audio Codec library
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+lib_LTLIBRARIES = libFLAC++.la
+noinst_LTLIBRARIES = libFLAC++-static.la
+
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libFLAC++.m4
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = flac++.pc
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	flac++.pc.in \
+	libFLAC++_dynamic.vcproj \
+	libFLAC++_dynamic.vcxproj \
+	libFLAC++_dynamic.vcxproj.filters \
+	libFLAC++_static.vcproj \
+	libFLAC++_static.vcxproj \
+	libFLAC++_static.vcxproj.filters \
+	libFLAC++.m4
+
+libFLAC___sources = \
+	metadata.cpp \
+	stream_decoder.cpp \
+	stream_encoder.cpp
+
+# see 'http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning' for numbering convention
+libFLAC___la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 9:0:3
+libFLAC___la_LIBADD = ../libFLAC/libFLAC.la
+libFLAC___la_SOURCES = $(libFLAC___sources)
+
+libFLAC___static_la_SOURCES = $(libFLAC___sources)
+libFLAC___static_la_LIBADD = ../libFLAC/libFLAC-static.la
diff --git a/src/libFLAC++/Makefile.lite b/src/libFLAC++/Makefile.lite
new file mode 100644
index 0000000..3853a01
--- /dev/null
+++ b/src/libFLAC++/Makefile.lite
@@ -0,0 +1,63 @@
+#  libFLAC++ - Free Lossless Audio Codec library
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+ifndef OS
+    OS := $(shell uname -s)
+endif
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm -lstdc++
+else
+ifeq ($(OS),FreeBSD)
+    LIBS = -lFLAC $(OGG_LIBS) -lm -lstdc++
+else
+    LIBS = -lFLAC $(OGG_LIBS) -lm -lsupc++
+endif
+endif
+
+LIB_NAME = libFLAC++
+INCLUDES = -I$(topdir)/include
+
+SRCS_CPP = \
+	metadata.cpp \
+	stream_decoder.cpp \
+	stream_encoder.cpp
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/libFLAC++/flac++.pc.in b/src/libFLAC++/flac++.pc.in
new file mode 100644
index 0000000..f09c251
--- /dev/null
+++ b/src/libFLAC++/flac++.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: FLAC++
+Description: Free Lossless Audio Codec Library (C++ API)
+Version: @VERSION@
+Requires: flac
+Libs: -L${libdir} -lFLAC++
+Cflags: -I${includedir}
diff --git a/src/libFLAC++/libFLAC++.m4 b/src/libFLAC++/libFLAC++.m4
new file mode 100644
index 0000000..d9e05f8
--- /dev/null
+++ b/src/libFLAC++/libFLAC++.m4
@@ -0,0 +1,117 @@
+# Configure paths for libFLAC++
+# "Inspired" by ogg.m4
+# Caller must first run AM_PATH_LIBFLAC
+
+dnl AM_PATH_LIBFLACPP([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libFLAC++, and define LIBFLACPP_CFLAGS, LIBFLACPP_LIBS, LIBFLACPP_LIBDIR
+dnl
+AC_DEFUN([AM_PATH_LIBFLACPP],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(libFLACPP,[  --with-libFLACPP=PFX   Prefix where libFLAC++ is installed (optional)], libFLACPP_prefix="$withval", libFLACPP_prefix="")
+AC_ARG_WITH(libFLACPP-libraries,[  --with-libFLACPP-libraries=DIR   Directory where libFLAC++ library is installed (optional)], libFLACPP_libraries="$withval", libFLACPP_libraries="")
+AC_ARG_WITH(libFLACPP-includes,[  --with-libFLACPP-includes=DIR   Directory where libFLAC++ header files are installed (optional)], libFLACPP_includes="$withval", libFLACPP_includes="")
+AC_ARG_ENABLE(libFLACPPtest, [  --disable-libFLACPPtest       Do not try to compile and run a test libFLAC++ program],, enable_libFLACPPtest=yes)
+
+  if test "x$libFLACPP_libraries" != "x" ; then
+    LIBFLACPP_LIBDIR="$libFLACPP_libraries"
+  elif test "x$libFLACPP_prefix" != "x" ; then
+    LIBFLACPP_LIBDIR="$libFLACPP_prefix/lib"
+  elif test "x$prefix" != "xNONE" ; then
+    LIBFLACPP_LIBDIR="$libdir"
+  fi
+
+  LIBFLACPP_LIBS="-L$LIBFLACPP_LIBDIR -lFLAC++ $LIBFLAC_LIBS"
+
+  if test "x$libFLACPP_includes" != "x" ; then
+    LIBFLACPP_CFLAGS="-I$libFLACPP_includes"
+  elif test "x$libFLACPP_prefix" != "x" ; then
+    LIBFLACPP_CFLAGS="-I$libFLACPP_prefix/include"
+  elif test "$prefix" != "xNONE"; then
+    LIBFLACPP_CFLAGS=""
+  fi
+
+  LIBFLACPP_CFLAGS="$LIBFLACPP_CFLAGS $LIBFLAC_CFLAGS"
+
+  AC_MSG_CHECKING(for libFLAC++)
+  no_libFLACPP=""
+
+
+  if test "x$enable_libFLACPPtest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_CXXFLAGS="$CXXFLAGS"
+    ac_save_LIBS="$LIBS"
+    ac_save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
+    CFLAGS="$CFLAGS $LIBFLACPP_CFLAGS"
+    CXXFLAGS="$CXXFLAGS $LIBFLACPP_CFLAGS"
+    LIBS="$LIBS $LIBFLACPP_LIBS"
+    LD_LIBRARY_PATH="$LIBFLACPP_LIBDIR:$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+dnl
+dnl Now check if the installed libFLAC++ is sufficiently new.
+dnl
+      rm -f conf.libFLAC++test
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FLAC++/decoder.h>
+
+int main ()
+{
+  system("touch conf.libFLAC++test");
+  return 0;
+}
+
+],, no_libFLACPP=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       CXXFLAGS="$ac_save_CXXFLAGS"
+       LIBS="$ac_save_LIBS"
+       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+  fi
+
+  if test "x$no_libFLACPP" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.libFLAC++test ; then
+       :
+     else
+       echo "*** Could not run libFLAC++ test program, checking why..."
+       CFLAGS="$CFLAGS $LIBFLACPP_CFLAGS"
+       CXXFLAGS="$CXXFLAGS $LIBFLACPP_CFLAGS"
+       LIBS="$LIBS $LIBFLACPP_LIBS"
+       LD_LIBRARY_PATH="$LIBFLACPP_LIBDIR:$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <FLAC++/decoder.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding libFLAC++ or finding the wrong"
+       echo "*** version of libFLAC++. If it is not finding libFLAC++, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occurred. This usually means libFLAC++ was incorrectly installed"
+       echo "*** or that you have moved libFLAC++ since it was installed. In the latter case, you"
+       echo "*** may want to edit the libFLAC++-config script: $LIBFLACPP_CONFIG" ])
+       CFLAGS="$ac_save_CFLAGS"
+       CXXFLAGS="$ac_save_CXXFLAGS"
+       LIBS="$ac_save_LIBS"
+       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+     fi
+     LIBFLACPP_CFLAGS=""
+     LIBFLACPP_LIBDIR=""
+     LIBFLACPP_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(LIBFLACPP_CFLAGS)
+  AC_SUBST(LIBFLACPP_LIBDIR)
+  AC_SUBST(LIBFLACPP_LIBS)
+  rm -f conf.libFLAC++test
+])
diff --git a/src/libFLAC++/libFLAC++_dynamic.vcproj b/src/libFLAC++/libFLAC++_dynamic.vcproj
new file mode 100644
index 0000000..e1ce90b
--- /dev/null
+++ b/src/libFLAC++/libFLAC++_dynamic.vcproj
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="libFLAC++_dynamic"

+	ProjectGUID="{4cefbc85-c215-11db-8314-0800200c9a66}"

+	RootNamespace="libFLAC++_dynamic"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)_dynamic"

+			ConfigurationType="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FLACPP_API_EXPORTS;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)_dynamic"

+			ConfigurationType="2"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FLACPP_API_EXPORTS"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\metadata.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_decoder.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder.cpp"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\include\FLAC++\all.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC++\decoder.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC++\encoder.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC++\export.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC++\metadata.h"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/libFLAC++/libFLAC++_dynamic.vcxproj b/src/libFLAC++/libFLAC++_dynamic.vcxproj
new file mode 100644
index 0000000..12b4fb0
--- /dev/null
+++ b/src/libFLAC++/libFLAC++_dynamic.vcxproj
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc85-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>libFLAC++_dynamic</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+    <IntDir>$(Configuration)_dynamic\</IntDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+    <IntDir>$(Platform)\$(Configuration)_dynamic\</IntDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+    <IntDir>$(Configuration)_dynamic\</IntDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+    <IntDir>$(Platform)\$(Configuration)_dynamic\</IntDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FLACPP_API_EXPORTS;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FLACPP_API_EXPORTS;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FLACPP_API_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FLACPP_API_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="metadata.cpp" />

+    <ClCompile Include="stream_decoder.cpp" />

+    <ClCompile Include="stream_encoder.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\include\FLAC++\all.h" />

+    <ClInclude Include="..\..\include\FLAC++\decoder.h" />

+    <ClInclude Include="..\..\include\FLAC++\encoder.h" />

+    <ClInclude Include="..\..\include\FLAC++\export.h" />

+    <ClInclude Include="..\..\include\FLAC++\metadata.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC\libFLAC_dynamic.vcxproj">

+      <Project>{4cefbc83-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/libFLAC++/libFLAC++_dynamic.vcxproj.filters b/src/libFLAC++/libFLAC++_dynamic.vcxproj.filters
new file mode 100644
index 0000000..8e64893
--- /dev/null
+++ b/src/libFLAC++/libFLAC++_dynamic.vcxproj.filters
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{a429b95c-ff8f-4d97-94ec-abfee2afd73c}</UniqueIdentifier>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="metadata.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_decoder.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\include\FLAC++\all.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC++\decoder.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC++\encoder.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC++\export.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC++\metadata.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/libFLAC++/libFLAC++_static.vcproj b/src/libFLAC++/libFLAC++_static.vcproj
new file mode 100644
index 0000000..20ee93b
--- /dev/null
+++ b/src/libFLAC++/libFLAC++_static.vcproj
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="libFLAC++_static"

+	ProjectGUID="{4cefbc86-c215-11db-8314-0800200c9a66}"

+	RootNamespace="libFLAC++_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\metadata.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_decoder.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder.cpp"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\include\FLAC++\all.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC++\decoder.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC++\encoder.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC++\export.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC++\metadata.h"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/libFLAC++/libFLAC++_static.vcxproj b/src/libFLAC++/libFLAC++_static.vcxproj
new file mode 100644
index 0000000..21994bd
--- /dev/null
+++ b/src/libFLAC++/libFLAC++_static.vcxproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc86-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>libFLAC++_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="metadata.cpp" />

+    <ClCompile Include="stream_decoder.cpp" />

+    <ClCompile Include="stream_encoder.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\include\FLAC++\all.h" />

+    <ClInclude Include="..\..\include\FLAC++\decoder.h" />

+    <ClInclude Include="..\..\include\FLAC++\encoder.h" />

+    <ClInclude Include="..\..\include\FLAC++\export.h" />

+    <ClInclude Include="..\..\include\FLAC++\metadata.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/libFLAC++/libFLAC++_static.vcxproj.filters b/src/libFLAC++/libFLAC++_static.vcxproj.filters
new file mode 100644
index 0000000..e34f01e
--- /dev/null
+++ b/src/libFLAC++/libFLAC++_static.vcxproj.filters
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{8fde5773-b1ca-496d-872f-5697b89aa10a}</UniqueIdentifier>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="metadata.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_decoder.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\include\FLAC++\all.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC++\decoder.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC++\encoder.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC++\export.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC++\metadata.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/libFLAC++/metadata.cpp b/src/libFLAC++/metadata.cpp
new file mode 100644
index 0000000..374e5b3
--- /dev/null
+++ b/src/libFLAC++/metadata.cpp
@@ -0,0 +1,1745 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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.
+ */
+
+#define __STDC_LIMIT_MACROS 1 /* otherwise SIZE_MAX is not defined for c++ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "share/alloc.h"
+#include "FLAC++/metadata.h"
+#include "FLAC/assert.h"
+#include <cstdlib> // for malloc(), free()
+#include <cstring> // for memcpy() etc.
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+namespace FLAC {
+	namespace Metadata {
+
+		// local utility routines
+
+		namespace local {
+
+			Prototype *construct_block(::FLAC__StreamMetadata *object)
+			{
+				if (0 == object)
+					return 0;
+
+				Prototype *ret = 0;
+				switch(object->type) {
+					case FLAC__METADATA_TYPE_STREAMINFO:
+						ret = new StreamInfo(object, /*copy=*/false);
+						break;
+					case FLAC__METADATA_TYPE_PADDING:
+						ret = new Padding(object, /*copy=*/false);
+						break;
+					case FLAC__METADATA_TYPE_APPLICATION:
+						ret = new Application(object, /*copy=*/false);
+						break;
+					case FLAC__METADATA_TYPE_SEEKTABLE:
+						ret = new SeekTable(object, /*copy=*/false);
+						break;
+					case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+						ret = new VorbisComment(object, /*copy=*/false);
+						break;
+					case FLAC__METADATA_TYPE_CUESHEET:
+						ret = new CueSheet(object, /*copy=*/false);
+						break;
+					case FLAC__METADATA_TYPE_PICTURE:
+						ret = new Picture(object, /*copy=*/false);
+						break;
+					default:
+						ret = new Unknown(object, /*copy=*/false);
+						break;
+				}
+				return ret;
+			}
+
+		} // namespace local
+
+		FLACPP_API Prototype *clone(const Prototype *object)
+		{
+			FLAC__ASSERT(0 != object);
+
+			const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
+			const Padding *padding = dynamic_cast<const Padding *>(object);
+			const Application *application = dynamic_cast<const Application *>(object);
+			const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
+			const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
+			const CueSheet *cuesheet = dynamic_cast<const CueSheet *>(object);
+			const Picture *picture = dynamic_cast<const Picture *>(object);
+			const Unknown *unknown = dynamic_cast<const Unknown *>(object);
+
+			if(0 != streaminfo)
+				return new StreamInfo(*streaminfo);
+			if(0 != padding)
+				return new Padding(*padding);
+			if(0 != application)
+				return new Application(*application);
+			if(0 != seektable)
+				return new SeekTable(*seektable);
+			if(0 != vorbiscomment)
+				return new VorbisComment(*vorbiscomment);
+			if(0 != cuesheet)
+				return new CueSheet(*cuesheet);
+			if(0 != picture)
+				return new Picture(*picture);
+			if(0 != unknown)
+				return new Unknown(*unknown);
+
+			FLAC__ASSERT(0);
+			return 0;
+		}
+
+		//
+		// Prototype
+		//
+
+		Prototype::Prototype(const Prototype &object):
+		object_(::FLAC__metadata_object_clone(object.object_)),
+		is_reference_(false)
+		{
+			FLAC__ASSERT(object.is_valid());
+		}
+
+		Prototype::Prototype(const ::FLAC__StreamMetadata &object):
+		object_(::FLAC__metadata_object_clone(&object)),
+		is_reference_(false)
+		{
+		}
+
+		Prototype::Prototype(const ::FLAC__StreamMetadata *object):
+		object_(::FLAC__metadata_object_clone(object)),
+		is_reference_(false)
+		{
+			FLAC__ASSERT(0 != object);
+		}
+
+		Prototype::Prototype(::FLAC__StreamMetadata *object, bool copy):
+		object_(copy? ::FLAC__metadata_object_clone(object) : object),
+		is_reference_(false)
+		{
+			FLAC__ASSERT(0 != object);
+		}
+
+		Prototype::~Prototype()
+		{
+			clear();
+		}
+
+		void Prototype::clear()
+		{
+			if(0 != object_ && !is_reference_)
+				FLAC__metadata_object_delete(object_);
+			object_ = 0;
+		}
+
+		Prototype &Prototype::operator=(const Prototype &object)
+		{
+			FLAC__ASSERT(object.is_valid());
+			clear();
+			is_reference_ = false;
+			object_ = ::FLAC__metadata_object_clone(object.object_);
+			return *this;
+		}
+
+		Prototype &Prototype::operator=(const ::FLAC__StreamMetadata &object)
+		{
+			clear();
+			is_reference_ = false;
+			object_ = ::FLAC__metadata_object_clone(&object);
+			return *this;
+		}
+
+		Prototype &Prototype::operator=(const ::FLAC__StreamMetadata *object)
+		{
+			FLAC__ASSERT(0 != object);
+			clear();
+			is_reference_ = false;
+			object_ = ::FLAC__metadata_object_clone(object);
+			return *this;
+		}
+
+		Prototype &Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy)
+		{
+			FLAC__ASSERT(0 != object);
+			clear();
+			object_ = (copy? ::FLAC__metadata_object_clone(object) : object);
+			is_reference_ = false;
+			return *this;
+		}
+
+		bool Prototype::get_is_last() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(object_->is_last);
+		}
+
+		FLAC__MetadataType Prototype::get_type() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->type;
+		}
+
+		uint32_t Prototype::get_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->length;
+		}
+
+		void Prototype::set_is_last(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			object_->is_last = value;
+		}
+
+
+		//
+		// StreamInfo
+		//
+
+		StreamInfo::StreamInfo():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false)
+		{ }
+
+		StreamInfo::~StreamInfo()
+		{ }
+
+		uint32_t StreamInfo::get_min_blocksize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.min_blocksize;
+		}
+
+		uint32_t StreamInfo::get_max_blocksize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.max_blocksize;
+		}
+
+		uint32_t StreamInfo::get_min_framesize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.min_framesize;
+		}
+
+		uint32_t StreamInfo::get_max_framesize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.max_framesize;
+		}
+
+		uint32_t StreamInfo::get_sample_rate() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.sample_rate;
+		}
+
+		uint32_t StreamInfo::get_channels() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.channels;
+		}
+
+		uint32_t StreamInfo::get_bits_per_sample() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.bits_per_sample;
+		}
+
+		FLAC__uint64 StreamInfo::get_total_samples() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.total_samples;
+		}
+
+		const FLAC__byte *StreamInfo::get_md5sum() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.md5sum;
+		}
+
+		void StreamInfo::set_min_blocksize(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
+			FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
+			object_->data.stream_info.min_blocksize = value;
+		}
+
+		void StreamInfo::set_max_blocksize(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
+			FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
+			object_->data.stream_info.max_blocksize = value;
+		}
+
+		void StreamInfo::set_min_framesize(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
+			object_->data.stream_info.min_framesize = value;
+		}
+
+		void StreamInfo::set_max_framesize(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
+			object_->data.stream_info.max_framesize = value;
+		}
+
+		void StreamInfo::set_sample_rate(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value));
+			object_->data.stream_info.sample_rate = value;
+		}
+
+		void StreamInfo::set_channels(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value > 0);
+			FLAC__ASSERT(value <= FLAC__MAX_CHANNELS);
+			object_->data.stream_info.channels = value;
+		}
+
+		void StreamInfo::set_bits_per_sample(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
+			FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
+			object_->data.stream_info.bits_per_sample = value;
+		}
+
+		void StreamInfo::set_total_samples(FLAC__uint64 value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value < (((FLAC__uint64)1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
+			object_->data.stream_info.total_samples = value;
+		}
+
+		void StreamInfo::set_md5sum(const FLAC__byte value[16])
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != value);
+			std::memcpy(object_->data.stream_info.md5sum, value, 16);
+		}
+
+
+		//
+		// Padding
+		//
+
+		Padding::Padding():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
+		{ }
+
+		Padding::Padding(uint32_t length):
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
+		{
+			set_length(length);
+		}
+
+		Padding::~Padding()
+		{ }
+
+		void Padding::set_length(uint32_t length)
+		{
+			FLAC__ASSERT(is_valid());
+			object_->length = length;
+		}
+
+
+		//
+		// Application
+		//
+
+		Application::Application():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
+		{ }
+
+		Application::~Application()
+		{ }
+
+		const FLAC__byte *Application::get_id() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.application.id;
+		}
+
+		const FLAC__byte *Application::get_data() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.application.data;
+		}
+
+		void Application::set_id(const FLAC__byte value[4])
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != value);
+			std::memcpy(object_->data.application.id, value, 4);
+		}
+
+		bool Application::set_data(const FLAC__byte *data, uint32_t length)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_application_set_data(object_, const_cast<FLAC__byte*>(data), length, true));
+		}
+
+		bool Application::set_data(FLAC__byte *data, uint32_t length, bool copy)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_application_set_data(object_, data, length, copy));
+		}
+
+
+		//
+		// SeekTable
+		//
+
+		SeekTable::SeekTable():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false)
+		{ }
+
+		SeekTable::~SeekTable()
+		{ }
+
+		uint32_t SeekTable::get_num_points() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.seek_table.num_points;
+		}
+
+		::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(uint32_t indx) const
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(indx < object_->data.seek_table.num_points);
+			return object_->data.seek_table.points[indx];
+		}
+
+		bool SeekTable::resize_points(uint32_t new_num_points)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_seektable_resize_points(object_, new_num_points));
+		}
+
+		void SeekTable::set_point(uint32_t indx, const ::FLAC__StreamMetadata_SeekPoint &point)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(indx < object_->data.seek_table.num_points);
+			::FLAC__metadata_object_seektable_set_point(object_, indx, point);
+		}
+
+		bool SeekTable::insert_point(uint32_t indx, const ::FLAC__StreamMetadata_SeekPoint &point)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(indx <= object_->data.seek_table.num_points);
+			return static_cast<bool>(::FLAC__metadata_object_seektable_insert_point(object_, indx, point));
+		}
+
+		bool SeekTable::delete_point(uint32_t indx)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(indx < object_->data.seek_table.num_points);
+			return static_cast<bool>(::FLAC__metadata_object_seektable_delete_point(object_, indx));
+		}
+
+		bool SeekTable::is_legal() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_seektable_is_legal(object_));
+		}
+
+		bool SeekTable::template_append_placeholders(uint32_t num)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_placeholders(object_, num));
+		}
+
+		bool SeekTable::template_append_point(FLAC__uint64 sample_number)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_point(object_, sample_number));
+		}
+
+		bool SeekTable::template_append_points(FLAC__uint64 sample_numbers[], uint32_t num)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_points(object_, sample_numbers, num));
+		}
+
+		bool SeekTable::template_append_spaced_points(uint32_t num, FLAC__uint64 total_samples)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_spaced_points(object_, num, total_samples));
+		}
+
+		bool SeekTable::template_append_spaced_points_by_samples(uint32_t samples, FLAC__uint64 total_samples)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(object_, samples, total_samples));
+		}
+
+		bool SeekTable::template_sort(bool compact)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_seektable_template_sort(object_, compact));
+		}
+
+
+		//
+		// VorbisComment::Entry
+		//
+
+		VorbisComment::Entry::Entry() :
+			is_valid_(true),
+			entry_(),
+			field_name_(0),
+			field_name_length_(0),
+			field_value_(0),
+			field_value_length_(0)
+		{
+			zero();
+		}
+
+		VorbisComment::Entry::Entry(const char *field, uint32_t field_length) :
+			is_valid_(true),
+			entry_(),
+			field_name_(0),
+			field_name_length_(0),
+			field_value_(0),
+			field_value_length_(0)
+		{
+			zero();
+			construct(field, field_length);
+		}
+
+		VorbisComment::Entry::Entry(const char *field) :
+			is_valid_(true),
+			entry_(),
+			field_name_(0),
+			field_name_length_(0),
+			field_value_(0),
+			field_value_length_(0)
+		{
+			zero();
+			construct(field);
+		}
+
+		VorbisComment::Entry::Entry(const char *field_name, const char *field_value, uint32_t field_value_length) :
+			is_valid_(true),
+			entry_(),
+			field_name_(0),
+			field_name_length_(0),
+			field_value_(0),
+			field_value_length_(0)
+		{
+			zero();
+			construct(field_name, field_value, field_value_length);
+		}
+
+		VorbisComment::Entry::Entry(const char *field_name, const char *field_value) :
+			is_valid_(true),
+			entry_(),
+			field_name_(0),
+			field_name_length_(0),
+			field_value_(0),
+			field_value_length_(0)
+		{
+			zero();
+			construct(field_name, field_value);
+		}
+
+		VorbisComment::Entry::Entry(const Entry &entry) :
+			is_valid_(true),
+			entry_(),
+			field_name_(0),
+			field_name_length_(0),
+			field_value_(0),
+			field_value_length_(0)
+		{
+			FLAC__ASSERT(entry.is_valid());
+			zero();
+			construct(reinterpret_cast<const char *>(entry.entry_.entry), entry.entry_.length);
+		}
+
+		VorbisComment::Entry &VorbisComment::Entry::operator=(const Entry &entry)
+		{
+			FLAC__ASSERT(entry.is_valid());
+			clear();
+			construct(reinterpret_cast<const char *>(entry.entry_.entry), entry.entry_.length);
+			return *this;
+		}
+
+		VorbisComment::Entry::~Entry()
+		{
+			clear();
+		}
+
+		bool VorbisComment::Entry::is_valid() const
+		{
+			return is_valid_;
+		}
+
+		uint32_t VorbisComment::Entry::get_field_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return entry_.length;
+		}
+
+		uint32_t VorbisComment::Entry::get_field_name_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return field_name_length_;
+		}
+
+		uint32_t VorbisComment::Entry::get_field_value_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return field_value_length_;
+		}
+
+		::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
+		{
+			FLAC__ASSERT(is_valid());
+			return entry_;
+		}
+
+		const char *VorbisComment::Entry::get_field() const
+		{
+			FLAC__ASSERT(is_valid());
+			return reinterpret_cast<const char *>(entry_.entry);
+		}
+
+		const char *VorbisComment::Entry::get_field_name() const
+		{
+			FLAC__ASSERT(is_valid());
+			return field_name_;
+		}
+
+		const char *VorbisComment::Entry::get_field_value() const
+		{
+			FLAC__ASSERT(is_valid());
+			return field_value_;
+		}
+
+		bool VorbisComment::Entry::set_field(const char *field, uint32_t field_length)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != field);
+
+			if(!::FLAC__format_vorbiscomment_entry_is_legal(reinterpret_cast<const ::FLAC__byte*>(field), field_length))
+				return is_valid_ = false;
+
+			clear_entry();
+
+			if(0 == (entry_.entry = static_cast<FLAC__byte*>(safe_malloc_add_2op_(field_length, /*+*/1)))) {
+				is_valid_ = false;
+			}
+			else {
+				entry_.length = field_length;
+				std::memcpy(entry_.entry, field, field_length);
+				entry_.entry[field_length] = '\0';
+				(void) parse_field();
+			}
+
+			return is_valid_;
+		}
+
+		bool VorbisComment::Entry::set_field(const char *field)
+		{
+			return set_field(field, std::strlen(field));
+		}
+
+		bool VorbisComment::Entry::set_field_name(const char *field_name)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != field_name);
+
+			if(!::FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
+				return is_valid_ = false;
+
+			clear_field_name();
+
+			if(0 == (field_name_ = strdup(field_name))) {
+				is_valid_ = false;
+			}
+			else {
+				field_name_length_ = std::strlen(field_name_);
+				compose_field();
+			}
+
+			return is_valid_;
+		}
+
+		bool VorbisComment::Entry::set_field_value(const char *field_value, uint32_t field_value_length)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != field_value);
+
+			if(!::FLAC__format_vorbiscomment_entry_value_is_legal(reinterpret_cast<const FLAC__byte*>(field_value), field_value_length))
+				return is_valid_ = false;
+
+			clear_field_value();
+
+			if(0 == (field_value_ = static_cast<char *>(safe_malloc_add_2op_(field_value_length, /*+*/1)))) {
+				is_valid_ = false;
+			}
+			else {
+				field_value_length_ = field_value_length;
+				std::memcpy(field_value_, field_value, field_value_length);
+				field_value_[field_value_length] = '\0';
+				compose_field();
+			}
+
+			return is_valid_;
+		}
+
+		bool VorbisComment::Entry::set_field_value(const char *field_value)
+		{
+			return set_field_value(field_value, std::strlen(field_value));
+		}
+
+		void VorbisComment::Entry::zero()
+		{
+			is_valid_ = true;
+			entry_.length = 0;
+			entry_.entry = 0;
+			field_name_ = 0;
+			field_name_length_ = 0;
+			field_value_ = 0;
+			field_value_length_ = 0;
+		}
+
+		void VorbisComment::Entry::clear()
+		{
+			clear_entry();
+			clear_field_name();
+			clear_field_value();
+			is_valid_ = true;
+		}
+
+		void VorbisComment::Entry::clear_entry()
+		{
+			if(0 != entry_.entry) {
+				std::free(entry_.entry);
+				entry_.entry = 0;
+				entry_.length = 0;
+			}
+		}
+
+		void VorbisComment::Entry::clear_field_name()
+		{
+			if(0 != field_name_) {
+				std::free(field_name_);
+				field_name_ = 0;
+				field_name_length_ = 0;
+			}
+		}
+
+		void VorbisComment::Entry::clear_field_value()
+		{
+			if(0 != field_value_) {
+				std::free(field_value_);
+				field_value_ = 0;
+				field_value_length_ = 0;
+			}
+		}
+
+		void VorbisComment::Entry::construct(const char *field, uint32_t field_length)
+		{
+			if(set_field(field, field_length))
+				parse_field();
+		}
+
+		void VorbisComment::Entry::construct(const char *field)
+		{
+			construct(field, std::strlen(field));
+		}
+
+		void VorbisComment::Entry::construct(const char *field_name, const char *field_value, uint32_t field_value_length)
+		{
+			if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
+				compose_field();
+		}
+
+		void VorbisComment::Entry::construct(const char *field_name, const char *field_value)
+		{
+			construct(field_name, field_value, std::strlen(field_value));
+		}
+
+		void VorbisComment::Entry::compose_field()
+		{
+			clear_entry();
+
+			if(0 == (entry_.entry = static_cast<FLAC__byte*>(safe_malloc_add_4op_(field_name_length_, /*+*/1, /*+*/field_value_length_, /*+*/1)))) {
+				is_valid_ = false;
+			}
+			else {
+				std::memcpy(entry_.entry, field_name_, field_name_length_);
+				entry_.length += field_name_length_;
+				std::memcpy(entry_.entry + entry_.length, "=", 1);
+				entry_.length += 1;
+				if (field_value_length_ > 0)
+					std::memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
+				entry_.length += field_value_length_;
+				entry_.entry[entry_.length] = '\0';
+				is_valid_ = true;
+			}
+		}
+
+		void VorbisComment::Entry::parse_field()
+		{
+			clear_field_name();
+			clear_field_value();
+
+			const char *p = static_cast<const char *>(std::memchr(entry_.entry, '=', entry_.length));
+
+			if(0 == p)
+				p = reinterpret_cast<const char *>(entry_.entry) + entry_.length;
+
+			field_name_length_ = static_cast<uint32_t>(p - reinterpret_cast<const char *>(entry_.entry));
+			if(0 == (field_name_ = static_cast<char *>(safe_malloc_add_2op_(field_name_length_, /*+*/1)))) { // +1 for the trailing \0
+				is_valid_ = false;
+				return;
+			}
+			std::memcpy(field_name_, entry_.entry, field_name_length_);
+			field_name_[field_name_length_] = '\0';
+
+			if(entry_.length - field_name_length_ == 0) {
+				field_value_length_ = 0;
+				if(0 == (field_value_ = static_cast<char *>(safe_malloc_(0)))) {
+					is_valid_ = false;
+					return;
+				}
+			}
+			else {
+				field_value_length_ = entry_.length - field_name_length_ - 1;
+				if(0 == (field_value_ = static_cast<char *>(safe_malloc_add_2op_(field_value_length_, /*+*/1)))) { // +1 for the trailing \0
+					is_valid_ = false;
+					return;
+				}
+				std::memcpy(field_value_, ++p, field_value_length_);
+				field_value_[field_value_length_] = '\0';
+			}
+
+			is_valid_ = true;
+		}
+
+
+		//
+		// VorbisComment
+		//
+
+		VorbisComment::VorbisComment():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
+		{ }
+
+		VorbisComment::~VorbisComment()
+		{ }
+
+		uint32_t VorbisComment::get_num_comments() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.vorbis_comment.num_comments;
+		}
+
+		const FLAC__byte *VorbisComment::get_vendor_string() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.vorbis_comment.vendor_string.entry;
+		}
+
+		VorbisComment::Entry VorbisComment::get_comment(uint32_t indx) const
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments);
+			return Entry(reinterpret_cast<const char *>(object_->data.vorbis_comment.comments[indx].entry), object_->data.vorbis_comment.comments[indx].length);
+		}
+
+		bool VorbisComment::set_vendor_string(const FLAC__byte *string)
+		{
+			FLAC__ASSERT(is_valid());
+			// vendor_string is a special kind of entry
+			const ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string = { static_cast<FLAC__uint32>(std::strlen(reinterpret_cast<const char *>(string))), const_cast<FLAC__byte*>(string) }; // we can cheat on const-ness because we make a copy below:
+			return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true));
+		}
+
+		bool VorbisComment::resize_comments(uint32_t new_num_comments)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_resize_comments(object_, new_num_comments));
+		}
+
+		bool VorbisComment::set_comment(uint32_t indx, const VorbisComment::Entry &entry)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments);
+			return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_set_comment(object_, indx, entry.get_entry(), /*copy=*/true));
+		}
+
+		bool VorbisComment::insert_comment(uint32_t indx, const VorbisComment::Entry &entry)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(indx <= object_->data.vorbis_comment.num_comments);
+			return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_insert_comment(object_, indx, entry.get_entry(), /*copy=*/true));
+		}
+
+		bool VorbisComment::append_comment(const VorbisComment::Entry &entry)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true));
+		}
+
+		bool VorbisComment::replace_comment(const VorbisComment::Entry &entry, bool all)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_replace_comment(object_, entry.get_entry(), static_cast<FLAC__bool>(all), /*copy=*/true));
+		}
+
+		bool VorbisComment::delete_comment(uint32_t indx)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments);
+			return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_delete_comment(object_, indx));
+		}
+
+		int VorbisComment::find_entry_from(uint32_t offset, const char *field_name)
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_object_vorbiscomment_find_entry_from(object_, offset, field_name);
+		}
+
+		int VorbisComment::remove_entry_matching(const char *field_name)
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_object_vorbiscomment_remove_entry_matching(object_, field_name);
+		}
+
+		int VorbisComment::remove_entries_matching(const char *field_name)
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_object_vorbiscomment_remove_entries_matching(object_, field_name);
+		}
+
+
+		//
+		// CueSheet::Track
+		//
+
+		CueSheet::Track::Track():
+		object_(::FLAC__metadata_object_cuesheet_track_new())
+		{ }
+
+		CueSheet::Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track *track):
+		object_(::FLAC__metadata_object_cuesheet_track_clone(track))
+		{ }
+
+		CueSheet::Track::Track(const Track &track):
+		object_(::FLAC__metadata_object_cuesheet_track_clone(track.object_))
+		{ }
+
+		CueSheet::Track &CueSheet::Track::operator=(const Track &track)
+		{
+			if(0 != object_)
+				::FLAC__metadata_object_cuesheet_track_delete(object_);
+			object_ = ::FLAC__metadata_object_cuesheet_track_clone(track.object_);
+			return *this;
+		}
+
+		CueSheet::Track::~Track()
+		{
+			if(0 != object_)
+				::FLAC__metadata_object_cuesheet_track_delete(object_);
+		}
+
+		bool CueSheet::Track::is_valid() const
+		{
+			return(0 != object_);
+		}
+
+		::FLAC__StreamMetadata_CueSheet_Index CueSheet::Track::get_index(uint32_t i) const
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(i < object_->num_indices);
+			return object_->indices[i];
+		}
+
+		void CueSheet::Track::set_isrc(const char value[12])
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != value);
+			std::memcpy(object_->isrc, value, 12);
+			object_->isrc[12] = '\0';
+		}
+
+		void CueSheet::Track::set_type(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value <= 1);
+			object_->type = value;
+		}
+
+ 		void CueSheet::Track::set_index(uint32_t i, const ::FLAC__StreamMetadata_CueSheet_Index &indx)
+ 		{
+ 			FLAC__ASSERT(is_valid());
+ 			FLAC__ASSERT(i < object_->num_indices);
+ 			object_->indices[i] = indx;
+ 		}
+
+
+		//
+		// CueSheet
+		//
+
+		CueSheet::CueSheet():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET), /*copy=*/false)
+		{ }
+
+		CueSheet::~CueSheet()
+		{ }
+
+		const char *CueSheet::get_media_catalog_number() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.cue_sheet.media_catalog_number;
+		}
+
+		FLAC__uint64 CueSheet::get_lead_in() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.cue_sheet.lead_in;
+		}
+
+		bool CueSheet::get_is_cd() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.cue_sheet.is_cd? true : false;
+		}
+
+		uint32_t CueSheet::get_num_tracks() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.cue_sheet.num_tracks;
+		}
+
+		CueSheet::Track CueSheet::get_track(uint32_t i) const
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
+			return Track(object_->data.cue_sheet.tracks + i);
+		}
+
+		void CueSheet::set_media_catalog_number(const char value[128])
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != value);
+			std::memcpy(object_->data.cue_sheet.media_catalog_number, value, 128);
+			object_->data.cue_sheet.media_catalog_number[128] = '\0';
+		}
+
+		void CueSheet::set_lead_in(FLAC__uint64 value)
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.cue_sheet.lead_in = value;
+		}
+
+		void CueSheet::set_is_cd(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.cue_sheet.is_cd = value;
+		}
+
+		void CueSheet::set_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &indx)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+			FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
+			object_->data.cue_sheet.tracks[track_num].indices[index_num] = indx;
+		}
+
+		bool CueSheet::resize_indices(uint32_t track_num, uint32_t new_num_indices)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_track_resize_indices(object_, track_num, new_num_indices));
+		}
+
+		bool CueSheet::insert_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &indx)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+			FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices);
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, indx));
+		}
+
+		bool CueSheet::insert_blank_index(uint32_t track_num, uint32_t index_num)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+			FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices);
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_track_insert_blank_index(object_, track_num, index_num));
+		}
+
+		bool CueSheet::delete_index(uint32_t track_num, uint32_t index_num)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+			FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num));
+		}
+
+		bool CueSheet::resize_tracks(uint32_t new_num_tracks)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_resize_tracks(object_, new_num_tracks));
+		}
+
+		bool CueSheet::set_track(uint32_t i, const CueSheet::Track &track)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
+			// We can safely const_cast since copy=true
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true));
+		}
+
+		bool CueSheet::insert_track(uint32_t i, const CueSheet::Track &track)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
+			// We can safely const_cast since copy=true
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true));
+		}
+
+		bool CueSheet::insert_blank_track(uint32_t i)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_insert_blank_track(object_, i));
+		}
+
+		bool CueSheet::delete_track(uint32_t i)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_delete_track(object_, i));
+		}
+
+		bool CueSheet::is_legal(bool check_cd_da_subset, const char **violation) const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation));
+		}
+
+		FLAC__uint32 CueSheet::calculate_cddb_id() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(object_);
+		}
+
+
+		//
+		// Picture
+		//
+
+		Picture::Picture():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false)
+		{ }
+
+		Picture::~Picture()
+		{ }
+
+		::FLAC__StreamMetadata_Picture_Type Picture::get_type() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.type;
+		}
+
+		const char *Picture::get_mime_type() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.mime_type;
+		}
+
+		const FLAC__byte *Picture::get_description() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.description;
+		}
+
+		FLAC__uint32 Picture::get_width() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.width;
+		}
+
+		FLAC__uint32 Picture::get_height() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.height;
+		}
+
+		FLAC__uint32 Picture::get_depth() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.depth;
+		}
+
+		FLAC__uint32 Picture::get_colors() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.colors;
+		}
+
+		FLAC__uint32 Picture::get_data_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.data_length;
+		}
+
+		const FLAC__byte *Picture::get_data() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.data;
+		}
+
+		void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type)
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.type = type;
+		}
+
+		bool Picture::set_mime_type(const char *string)
+		{
+			FLAC__ASSERT(is_valid());
+			// We can safely const_cast since copy=true
+			return static_cast<bool>(::FLAC__metadata_object_picture_set_mime_type(object_, const_cast<char*>(string), /*copy=*/true));
+		}
+
+		bool Picture::set_description(const FLAC__byte *string)
+		{
+			FLAC__ASSERT(is_valid());
+			// We can safely const_cast since copy=true
+			return static_cast<bool>(::FLAC__metadata_object_picture_set_description(object_, const_cast<FLAC__byte*>(string), /*copy=*/true));
+		}
+
+		void Picture::set_width(FLAC__uint32 value) const
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.width = value;
+		}
+
+		void Picture::set_height(FLAC__uint32 value) const
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.height = value;
+		}
+
+		void Picture::set_depth(FLAC__uint32 value) const
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.depth = value;
+		}
+
+		void Picture::set_colors(FLAC__uint32 value) const
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.colors = value;
+		}
+
+		bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length)
+		{
+			FLAC__ASSERT(is_valid());
+			// We can safely const_cast since copy=true
+			return static_cast<bool>(::FLAC__metadata_object_picture_set_data(object_, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true));
+		}
+
+		bool Picture::is_legal(const char **violation)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_picture_is_legal(object_, violation));
+		}
+
+
+		//
+		// Unknown
+		//
+
+		Unknown::Unknown():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
+		{ }
+
+		Unknown::~Unknown()
+		{ }
+
+		const FLAC__byte *Unknown::get_data() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.application.data;
+		}
+
+		bool Unknown::set_data(const FLAC__byte *data, uint32_t length)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_application_set_data(object_, const_cast<FLAC__byte*>(data), length, true));
+		}
+
+		bool Unknown::set_data(FLAC__byte *data, uint32_t length, bool copy)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_object_application_set_data(object_, data, length, copy));
+		}
+
+
+		// ============================================================
+		//
+		//  Level 0
+		//
+		// ============================================================
+
+		FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata object;
+
+			if(::FLAC__metadata_get_streaminfo(filename, &object)) {
+				streaminfo = object;
+				return true;
+			}
+			else
+				return false;
+		}
+
+		FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata *object;
+
+			tags = 0;
+
+			if(::FLAC__metadata_get_tags(filename, &object)) {
+				tags = new VorbisComment(object, /*copy=*/false);
+				return true;
+			}
+			else
+				return false;
+		}
+
+		FLACPP_API bool get_tags(const char *filename, VorbisComment &tags)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata *object;
+
+			if(::FLAC__metadata_get_tags(filename, &object)) {
+				tags.assign(object, /*copy=*/false);
+				return true;
+			}
+			else
+				return false;
+		}
+
+		FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata *object;
+
+			cuesheet = 0;
+
+			if(::FLAC__metadata_get_cuesheet(filename, &object)) {
+				cuesheet = new CueSheet(object, /*copy=*/false);
+				return true;
+			}
+			else
+				return false;
+		}
+
+		FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata *object;
+
+			if(::FLAC__metadata_get_cuesheet(filename, &object)) {
+				cuesheet.assign(object, /*copy=*/false);
+				return true;
+			}
+			else
+				return false;
+		}
+
+		FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata *object;
+
+			picture = 0;
+
+			if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
+				picture = new Picture(object, /*copy=*/false);
+				return true;
+			}
+			else
+				return false;
+		}
+
+		FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata *object;
+
+			if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
+				picture.assign(object, /*copy=*/false);
+				return true;
+			}
+			else
+				return false;
+		}
+
+
+		// ============================================================
+		//
+		//  Level 1
+		//
+		// ============================================================
+
+		SimpleIterator::SimpleIterator():
+		iterator_(::FLAC__metadata_simple_iterator_new())
+		{ }
+
+		SimpleIterator::~SimpleIterator()
+		{
+			clear();
+		}
+
+		void SimpleIterator::clear()
+		{
+			if(0 != iterator_)
+				FLAC__metadata_simple_iterator_delete(iterator_);
+			iterator_ = 0;
+		}
+
+		bool SimpleIterator::init(const char *filename, bool read_only, bool preserve_file_stats)
+		{
+			FLAC__ASSERT(0 != filename);
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats));
+		}
+
+		bool SimpleIterator::is_valid() const
+		{
+			return 0 != iterator_;
+		}
+
+		SimpleIterator::Status SimpleIterator::status()
+		{
+			FLAC__ASSERT(is_valid());
+			return Status(::FLAC__metadata_simple_iterator_status(iterator_));
+		}
+
+		bool SimpleIterator::is_writable() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_is_writable(iterator_));
+		}
+
+		bool SimpleIterator::next()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_next(iterator_));
+		}
+
+		bool SimpleIterator::prev()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_prev(iterator_));
+		}
+
+		//@@@@ add to tests
+		bool SimpleIterator::is_last() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_is_last(iterator_));
+		}
+
+		//@@@@ add to tests
+		off_t SimpleIterator::get_block_offset() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_simple_iterator_get_block_offset(iterator_);
+		}
+
+		::FLAC__MetadataType SimpleIterator::get_block_type() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
+		}
+
+		//@@@@ add to tests
+		uint32_t SimpleIterator::get_block_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_simple_iterator_get_block_length(iterator_);
+		}
+
+		//@@@@ add to tests
+		bool SimpleIterator::get_application_id(FLAC__byte *id)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_get_application_id(iterator_, id));
+		}
+
+		Prototype *SimpleIterator::get_block()
+		{
+			FLAC__ASSERT(is_valid());
+			return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
+		}
+
+		bool SimpleIterator::set_block(Prototype *block, bool use_padding)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding));
+		}
+
+		bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding));
+		}
+
+		bool SimpleIterator::delete_block(bool use_padding)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding));
+		}
+
+
+		// ============================================================
+		//
+		//  Level 2
+		//
+		// ============================================================
+
+		Chain::Chain():
+		chain_(::FLAC__metadata_chain_new())
+		{ }
+
+		Chain::~Chain()
+		{
+			clear();
+		}
+
+		void Chain::clear()
+		{
+			if(0 != chain_)
+				FLAC__metadata_chain_delete(chain_);
+			chain_ = 0;
+		}
+
+		bool Chain::is_valid() const
+		{
+			return 0 != chain_;
+		}
+
+		Chain::Status Chain::status()
+		{
+			FLAC__ASSERT(is_valid());
+			return Status(::FLAC__metadata_chain_status(chain_));
+		}
+
+		bool Chain::read(const char *filename, bool is_ogg)
+		{
+			FLAC__ASSERT(0 != filename);
+			FLAC__ASSERT(is_valid());
+			return is_ogg?
+				static_cast<bool>(::FLAC__metadata_chain_read_ogg(chain_, filename)) :
+				static_cast<bool>(::FLAC__metadata_chain_read(chain_, filename))
+			;
+		}
+
+		bool Chain::read(FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, bool is_ogg)
+		{
+			FLAC__ASSERT(is_valid());
+			return is_ogg?
+				static_cast<bool>(::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks)) :
+				static_cast<bool>(::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks))
+			;
+		}
+
+		bool Chain::check_if_tempfile_needed(bool use_padding)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding));
+		}
+
+		bool Chain::write(bool use_padding, bool preserve_file_stats)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats));
+		}
+
+		bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks));
+		}
+
+		bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks));
+		}
+
+		void Chain::merge_padding()
+		{
+			FLAC__ASSERT(is_valid());
+			::FLAC__metadata_chain_merge_padding(chain_);
+		}
+
+		void Chain::sort_padding()
+		{
+			FLAC__ASSERT(is_valid());
+			::FLAC__metadata_chain_sort_padding(chain_);
+		}
+
+
+		Iterator::Iterator():
+		iterator_(::FLAC__metadata_iterator_new())
+		{ }
+
+		Iterator::~Iterator()
+		{
+			clear();
+		}
+
+		void Iterator::clear()
+		{
+			if(0 != iterator_)
+				FLAC__metadata_iterator_delete(iterator_);
+			iterator_ = 0;
+		}
+
+		bool Iterator::is_valid() const
+		{
+			return 0 != iterator_;
+		}
+
+		void Iterator::init(Chain &chain)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(chain.is_valid());
+			::FLAC__metadata_iterator_init(iterator_, chain.chain_);
+		}
+
+		bool Iterator::next()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_iterator_next(iterator_));
+		}
+
+		bool Iterator::prev()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_iterator_prev(iterator_));
+		}
+
+		::FLAC__MetadataType Iterator::get_block_type() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_iterator_get_block_type(iterator_);
+		}
+
+		Prototype *Iterator::get_block()
+		{
+			FLAC__ASSERT(is_valid());
+			Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
+			if(0 != block)
+				block->set_reference(true);
+			return block;
+		}
+
+		bool Iterator::set_block(Prototype *block)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			bool ret = static_cast<bool>(::FLAC__metadata_iterator_set_block(iterator_, block->object_));
+			if(ret) {
+				block->set_reference(true);
+				delete block;
+			}
+			return ret;
+		}
+
+		bool Iterator::delete_block(bool replace_with_padding)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding));
+		}
+
+		bool Iterator::insert_block_before(Prototype *block)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			bool ret = static_cast<bool>(::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_));
+			if(ret) {
+				block->set_reference(true);
+				delete block;
+			}
+			return ret;
+		}
+
+		bool Iterator::insert_block_after(Prototype *block)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			bool ret = static_cast<bool>(::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_));
+			if(ret) {
+				block->set_reference(true);
+				delete block;
+			}
+			return ret;
+		}
+
+	} // namespace Metadata
+} // namespace FLAC
diff --git a/src/libFLAC++/stream_decoder.cpp b/src/libFLAC++/stream_decoder.cpp
new file mode 100644
index 0000000..b375025
--- /dev/null
+++ b/src/libFLAC++/stream_decoder.cpp
@@ -0,0 +1,394 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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++/decoder.h"
+#include "FLAC/assert.h"
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+namespace FLAC {
+	namespace Decoder {
+
+		// ------------------------------------------------------------
+		//
+		// Stream
+		//
+		// ------------------------------------------------------------
+
+		Stream::Stream():
+		decoder_(::FLAC__stream_decoder_new())
+		{ }
+
+		Stream::~Stream()
+		{
+			if(0 != decoder_) {
+				(void)::FLAC__stream_decoder_finish(decoder_);
+				::FLAC__stream_decoder_delete(decoder_);
+			}
+		}
+
+		bool Stream::is_valid() const
+		{
+			return 0 != decoder_;
+		}
+
+		bool Stream::set_ogg_serial_number(long value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_set_ogg_serial_number(decoder_, value));
+		}
+
+		bool Stream::set_md5_checking(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_set_md5_checking(decoder_, value));
+		}
+
+		bool Stream::set_metadata_respond(::FLAC__MetadataType type)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_set_metadata_respond(decoder_, type));
+		}
+
+		bool Stream::set_metadata_respond_application(const FLAC__byte id[4])
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_set_metadata_respond_application(decoder_, id));
+		}
+
+		bool Stream::set_metadata_respond_all()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_set_metadata_respond_all(decoder_));
+		}
+
+		bool Stream::set_metadata_ignore(::FLAC__MetadataType type)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_set_metadata_ignore(decoder_, type));
+		}
+
+		bool Stream::set_metadata_ignore_application(const FLAC__byte id[4])
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_set_metadata_ignore_application(decoder_, id));
+		}
+
+		bool Stream::set_metadata_ignore_all()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_set_metadata_ignore_all(decoder_));
+		}
+
+		Stream::State Stream::get_state() const
+		{
+			FLAC__ASSERT(is_valid());
+			return State(::FLAC__stream_decoder_get_state(decoder_));
+		}
+
+		bool Stream::get_md5_checking() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_get_md5_checking(decoder_));
+		}
+
+		FLAC__uint64 Stream::get_total_samples() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_get_total_samples(decoder_);
+		}
+
+		uint32_t Stream::get_channels() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_get_channels(decoder_);
+		}
+
+		::FLAC__ChannelAssignment Stream::get_channel_assignment() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_get_channel_assignment(decoder_);
+		}
+
+		uint32_t Stream::get_bits_per_sample() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_get_bits_per_sample(decoder_);
+		}
+
+		uint32_t Stream::get_sample_rate() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_get_sample_rate(decoder_);
+		}
+
+		uint32_t Stream::get_blocksize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_get_blocksize(decoder_);
+		}
+
+		bool Stream::get_decode_position(FLAC__uint64 *position) const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_get_decode_position(decoder_, position);
+		}
+
+		::FLAC__StreamDecoderInitStatus Stream::init()
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_init_stream(decoder_, read_callback_, seek_callback_, tell_callback_, length_callback_, eof_callback_, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamDecoderInitStatus Stream::init_ogg()
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_decoder_init_ogg_stream(decoder_, read_callback_, seek_callback_, tell_callback_, length_callback_, eof_callback_, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+		}
+
+		bool Stream::finish()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_finish(decoder_));
+		}
+
+		bool Stream::flush()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_flush(decoder_));
+		}
+
+		bool Stream::reset()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_reset(decoder_));
+		}
+
+		bool Stream::process_single()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_process_single(decoder_));
+		}
+
+		bool Stream::process_until_end_of_metadata()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_process_until_end_of_metadata(decoder_));
+		}
+
+		bool Stream::process_until_end_of_stream()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_process_until_end_of_stream(decoder_));
+		}
+
+		bool Stream::skip_single_frame()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_skip_single_frame(decoder_));
+		}
+
+		bool Stream::seek_absolute(FLAC__uint64 sample)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_decoder_seek_absolute(decoder_, sample));
+		}
+
+		::FLAC__StreamDecoderSeekStatus Stream::seek_callback(FLAC__uint64 absolute_byte_offset)
+		{
+			(void)absolute_byte_offset;
+			return ::FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+		}
+
+		::FLAC__StreamDecoderTellStatus Stream::tell_callback(FLAC__uint64 *absolute_byte_offset)
+		{
+			(void)absolute_byte_offset;
+			return ::FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+		}
+
+		::FLAC__StreamDecoderLengthStatus Stream::length_callback(FLAC__uint64 *stream_length)
+		{
+			(void)stream_length;
+			return ::FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+		}
+
+		bool Stream::eof_callback()
+		{
+			return false;
+		}
+
+		void Stream::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+		{
+			(void)metadata;
+		}
+
+		::FLAC__StreamDecoderReadStatus Stream::read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+		{
+			(void)decoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->read_callback(buffer, bytes);
+		}
+
+		::FLAC__StreamDecoderSeekStatus Stream::seek_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+		{
+			(void) decoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->seek_callback(absolute_byte_offset);
+		}
+
+		::FLAC__StreamDecoderTellStatus Stream::tell_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+		{
+			(void) decoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->tell_callback(absolute_byte_offset);
+		}
+
+		::FLAC__StreamDecoderLengthStatus Stream::length_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+		{
+			(void) decoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->length_callback(stream_length);
+		}
+
+		FLAC__bool Stream::eof_callback_(const ::FLAC__StreamDecoder *decoder, void *client_data)
+		{
+			(void) decoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->eof_callback();
+		}
+
+		::FLAC__StreamDecoderWriteStatus Stream::write_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+		{
+			(void)decoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->write_callback(frame, buffer);
+		}
+
+		void Stream::metadata_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
+		{
+			(void)decoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			instance->metadata_callback(metadata);
+		}
+
+		void Stream::error_callback_(const ::FLAC__StreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data)
+		{
+			(void)decoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			instance->error_callback(status);
+		}
+
+		// ------------------------------------------------------------
+		//
+		// File
+		//
+		// ------------------------------------------------------------
+
+		File::File():
+			Stream()
+		{ }
+
+		File::~File()
+		{
+		}
+
+		::FLAC__StreamDecoderInitStatus File::init(FILE *file)
+		{
+			FLAC__ASSERT(0 != decoder_);
+			return ::FLAC__stream_decoder_init_FILE(decoder_, file, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamDecoderInitStatus File::init(const char *filename)
+		{
+			FLAC__ASSERT(0 != decoder_);
+			return ::FLAC__stream_decoder_init_file(decoder_, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamDecoderInitStatus File::init(const std::string &filename)
+		{
+			return init(filename.c_str());
+		}
+
+		::FLAC__StreamDecoderInitStatus File::init_ogg(FILE *file)
+		{
+			FLAC__ASSERT(0 != decoder_);
+			return ::FLAC__stream_decoder_init_ogg_FILE(decoder_, file, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamDecoderInitStatus File::init_ogg(const char *filename)
+		{
+			FLAC__ASSERT(0 != decoder_);
+			return ::FLAC__stream_decoder_init_ogg_file(decoder_, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamDecoderInitStatus File::init_ogg(const std::string &filename)
+		{
+			return init_ogg(filename.c_str());
+		}
+
+		// This is a dummy to satisfy the pure virtual from Stream; the
+		// read callback will never be called since we are initializing
+		// with FLAC__stream_decoder_init_FILE() or
+		// FLAC__stream_decoder_init_file() and those supply the read
+		// callback internally.
+		::FLAC__StreamDecoderReadStatus File::read_callback(FLAC__byte buffer[], size_t *bytes)
+		{
+			(void)buffer, (void)bytes;
+			FLAC__ASSERT(false);
+			return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT; // double protection
+		}
+
+	} // namespace Decoder
+} // namespace FLAC
diff --git a/src/libFLAC++/stream_encoder.cpp b/src/libFLAC++/stream_encoder.cpp
new file mode 100644
index 0000000..1e04784
--- /dev/null
+++ b/src/libFLAC++/stream_encoder.cpp
@@ -0,0 +1,516 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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++/encoder.h"
+#include "FLAC++/metadata.h"
+#include "FLAC/assert.h"
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+namespace FLAC {
+	namespace Encoder {
+
+		// ------------------------------------------------------------
+		//
+		// Stream
+		//
+		// ------------------------------------------------------------
+
+		Stream::Stream():
+		encoder_(::FLAC__stream_encoder_new())
+		{ }
+
+		Stream::~Stream()
+		{
+			if(0 != encoder_) {
+				(void)::FLAC__stream_encoder_finish(encoder_);
+				::FLAC__stream_encoder_delete(encoder_);
+			}
+		}
+
+		bool Stream::is_valid() const
+		{
+			return 0 != encoder_;
+		}
+
+		bool Stream::set_ogg_serial_number(long value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_ogg_serial_number(encoder_, value));
+		}
+
+		bool Stream::set_verify(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_verify(encoder_, value));
+		}
+
+		bool Stream::set_streamable_subset(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_streamable_subset(encoder_, value));
+		}
+
+		bool Stream::set_channels(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_channels(encoder_, value));
+		}
+
+		bool Stream::set_bits_per_sample(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_bits_per_sample(encoder_, value));
+		}
+
+		bool Stream::set_sample_rate(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_sample_rate(encoder_, value));
+		}
+
+		bool Stream::set_compression_level(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_compression_level(encoder_, value));
+		}
+
+		bool Stream::set_blocksize(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_blocksize(encoder_, value));
+		}
+
+		bool Stream::set_do_mid_side_stereo(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_do_mid_side_stereo(encoder_, value));
+		}
+
+		bool Stream::set_loose_mid_side_stereo(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_loose_mid_side_stereo(encoder_, value));
+		}
+
+		bool Stream::set_apodization(const char *specification)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_apodization(encoder_, specification));
+		}
+
+		bool Stream::set_max_lpc_order(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_max_lpc_order(encoder_, value));
+		}
+
+		bool Stream::set_qlp_coeff_precision(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_qlp_coeff_precision(encoder_, value));
+		}
+
+		bool Stream::set_do_qlp_coeff_prec_search(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder_, value));
+		}
+
+		bool Stream::set_do_escape_coding(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_do_escape_coding(encoder_, value));
+		}
+
+		bool Stream::set_do_exhaustive_model_search(bool value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_do_exhaustive_model_search(encoder_, value));
+		}
+
+		bool Stream::set_min_residual_partition_order(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_min_residual_partition_order(encoder_, value));
+		}
+
+		bool Stream::set_max_residual_partition_order(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_max_residual_partition_order(encoder_, value));
+		}
+
+		bool Stream::set_rice_parameter_search_dist(uint32_t value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_rice_parameter_search_dist(encoder_, value));
+		}
+
+		bool Stream::set_total_samples_estimate(FLAC__uint64 value)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_total_samples_estimate(encoder_, value));
+		}
+
+		bool Stream::set_metadata(::FLAC__StreamMetadata **metadata, uint32_t num_blocks)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_set_metadata(encoder_, metadata, num_blocks));
+		}
+
+		bool Stream::set_metadata(FLAC::Metadata::Prototype **metadata, uint32_t num_blocks)
+		{
+			FLAC__ASSERT(is_valid());
+#ifndef HAVE_CXX_VARARRAYS
+			// some compilers (MSVC++, Borland C, SunPro, some GCCs w/ -pedantic) can't handle:
+			// ::FLAC__StreamMetadata *m[num_blocks];
+			// so we do this ugly workaround
+			::FLAC__StreamMetadata **m = new ::FLAC__StreamMetadata*[num_blocks];
+#else
+			::FLAC__StreamMetadata *m[num_blocks];
+#endif
+			for(uint32_t i = 0; i < num_blocks; i++) {
+				// we can get away with the const_cast since we know the encoder will only correct the is_last flags
+				m[i] = const_cast< ::FLAC__StreamMetadata*>(static_cast<const ::FLAC__StreamMetadata*>(*metadata[i]));
+			}
+#ifndef HAVE_CXX_VARARRAYS
+			// complete the hack
+			const bool ok = static_cast<bool>(::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks));
+			delete [] m;
+			return ok;
+#else
+			return static_cast<bool>(::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks));
+#endif
+		}
+
+		Stream::State Stream::get_state() const
+		{
+			FLAC__ASSERT(is_valid());
+			return State(::FLAC__stream_encoder_get_state(encoder_));
+		}
+
+		Decoder::Stream::State Stream::get_verify_decoder_state() const
+		{
+			FLAC__ASSERT(is_valid());
+			return Decoder::Stream::State(::FLAC__stream_encoder_get_verify_decoder_state(encoder_));
+		}
+
+		void Stream::get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got)
+		{
+			FLAC__ASSERT(is_valid());
+			::FLAC__stream_encoder_get_verify_decoder_error_stats(encoder_, absolute_sample, frame_number, channel, sample, expected, got);
+		}
+
+		bool Stream::get_verify() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_get_verify(encoder_));
+		}
+
+		bool Stream::get_streamable_subset() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_get_streamable_subset(encoder_));
+		}
+
+		bool Stream::get_do_mid_side_stereo() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_get_do_mid_side_stereo(encoder_));
+		}
+
+		bool Stream::get_loose_mid_side_stereo() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_get_loose_mid_side_stereo(encoder_));
+		}
+
+		uint32_t Stream::get_channels() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_channels(encoder_);
+		}
+
+		uint32_t Stream::get_bits_per_sample() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_bits_per_sample(encoder_);
+		}
+
+		uint32_t Stream::get_sample_rate() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_sample_rate(encoder_);
+		}
+
+		uint32_t Stream::get_blocksize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_blocksize(encoder_);
+		}
+
+		uint32_t Stream::get_max_lpc_order() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_max_lpc_order(encoder_);
+		}
+
+		uint32_t Stream::get_qlp_coeff_precision() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_qlp_coeff_precision(encoder_);
+		}
+
+		bool Stream::get_do_qlp_coeff_prec_search() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder_));
+		}
+
+		bool Stream::get_do_escape_coding() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_get_do_escape_coding(encoder_));
+		}
+
+		bool Stream::get_do_exhaustive_model_search() const
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_get_do_exhaustive_model_search(encoder_));
+		}
+
+		uint32_t Stream::get_min_residual_partition_order() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_min_residual_partition_order(encoder_);
+		}
+
+		uint32_t Stream::get_max_residual_partition_order() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_max_residual_partition_order(encoder_);
+		}
+
+		uint32_t Stream::get_rice_parameter_search_dist() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_rice_parameter_search_dist(encoder_);
+		}
+
+		FLAC__uint64 Stream::get_total_samples_estimate() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_get_total_samples_estimate(encoder_);
+		}
+
+		::FLAC__StreamEncoderInitStatus Stream::init()
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_init_stream(encoder_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamEncoderInitStatus Stream::init_ogg()
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_init_ogg_stream(encoder_, read_callback_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*)this);
+		}
+
+		bool Stream::finish()
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_finish(encoder_));
+		}
+
+		bool Stream::process(const FLAC__int32 * const buffer[], uint32_t samples)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_process(encoder_, buffer, samples));
+		}
+
+		bool Stream::process_interleaved(const FLAC__int32 buffer[], uint32_t samples)
+		{
+			FLAC__ASSERT(is_valid());
+			return static_cast<bool>(::FLAC__stream_encoder_process_interleaved(encoder_, buffer, samples));
+		}
+
+		::FLAC__StreamEncoderReadStatus Stream::read_callback(FLAC__byte buffer[], size_t *bytes)
+		{
+			(void)buffer, (void)bytes;
+			return ::FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED;
+		}
+
+		::FLAC__StreamEncoderSeekStatus Stream::seek_callback(FLAC__uint64 absolute_byte_offset)
+		{
+			(void)absolute_byte_offset;
+			return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+		}
+
+		::FLAC__StreamEncoderTellStatus Stream::tell_callback(FLAC__uint64 *absolute_byte_offset)
+		{
+			(void)absolute_byte_offset;
+			return ::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
+		}
+
+		void Stream::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+		{
+			(void)metadata;
+		}
+
+		::FLAC__StreamEncoderReadStatus Stream::read_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+		{
+			(void)encoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->read_callback(buffer, bytes);
+		}
+
+		::FLAC__StreamEncoderWriteStatus Stream::write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data)
+		{
+			(void)encoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->write_callback(buffer, bytes, samples, current_frame);
+		}
+
+		::FLAC__StreamEncoderSeekStatus Stream::seek_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+		{
+			(void)encoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->seek_callback(absolute_byte_offset);
+		}
+
+		::FLAC__StreamEncoderTellStatus Stream::tell_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+		{
+			(void)encoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			return instance->tell_callback(absolute_byte_offset);
+		}
+
+		void Stream::metadata_callback_(const ::FLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
+		{
+			(void)encoder;
+			FLAC__ASSERT(0 != client_data);
+			Stream *instance = reinterpret_cast<Stream *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			instance->metadata_callback(metadata);
+		}
+
+		// ------------------------------------------------------------
+		//
+		// File
+		//
+		// ------------------------------------------------------------
+
+		File::File():
+			Stream()
+		{ }
+
+		File::~File()
+		{
+		}
+
+		::FLAC__StreamEncoderInitStatus File::init(FILE *file)
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_init_FILE(encoder_, file, progress_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamEncoderInitStatus File::init(const char *filename)
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_init_file(encoder_, filename, progress_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamEncoderInitStatus File::init(const std::string &filename)
+		{
+			return init(filename.c_str());
+		}
+
+		::FLAC__StreamEncoderInitStatus File::init_ogg(FILE *file)
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_init_ogg_FILE(encoder_, file, progress_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamEncoderInitStatus File::init_ogg(const char *filename)
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__stream_encoder_init_ogg_file(encoder_, filename, progress_callback_, /*client_data=*/(void*)this);
+		}
+
+		::FLAC__StreamEncoderInitStatus File::init_ogg(const std::string &filename)
+		{
+			return init_ogg(filename.c_str());
+		}
+
+		// This is a dummy to satisfy the pure virtual from Stream; the
+		// read callback will never be called since we are initializing
+		// with FLAC__stream_decoder_init_FILE() or
+		// FLAC__stream_decoder_init_file() and those supply the read
+		// callback internally.
+		::FLAC__StreamEncoderWriteStatus File::write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame)
+		{
+			(void)buffer, (void)bytes, (void)samples, (void)current_frame;
+			FLAC__ASSERT(false);
+			return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; // double protection
+		}
+
+		void File::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate)
+		{
+			(void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate;
+		}
+
+		void File::progress_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data)
+		{
+			(void)encoder;
+			FLAC__ASSERT(0 != client_data);
+			File *instance = reinterpret_cast<File *>(client_data);
+			FLAC__ASSERT(0 != instance);
+			instance->progress_callback(bytes_written, samples_written, frames_written, total_frames_estimate);
+		}
+
+	} // namespace Encoder
+} // namespace FLAC
diff --git a/src/libFLAC/Android.bp b/src/libFLAC/Android.bp
new file mode 100644
index 0000000..3d32da2
--- /dev/null
+++ b/src/libFLAC/Android.bp
@@ -0,0 +1,78 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "external_flac_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-BSD
+    //   legacy_unencumbered
+    default_applicable_licenses: ["external_flac_license"],
+}
+
+cc_library_static {
+    name: "libFLAC",
+    vendor_available: true,
+    host_supported: true,
+    srcs: [
+        "bitmath.c",
+        "bitreader.c",
+        "bitwriter.c",
+        "cpu.c",
+        "crc.c",
+        "fixed.c",
+        "float.c",
+        "format.c",
+        "lpc.c",
+        "memory.c",
+        "md5.c",
+        "stream_decoder.c",
+        "stream_encoder.c",
+        "stream_encoder_framing.c",
+        "window.c",
+    ],
+
+    local_include_dirs: ["include"],
+    header_libs: [
+        "libFLAC-config",
+        "libFLAC-headers",
+    ],
+    export_header_lib_headers: ["libFLAC-headers"],
+
+    cflags: [
+        "-DHAVE_CONFIG_H",
+        "-DFLAC__NO_MD5",
+        "-DFLAC__INTEGER_ONLY_LIBRARY",
+
+        "-D_REENTRANT",
+        "-DPIC",
+        "-DU_COMMON_IMPLEMENTATION",
+        "-fPIC",
+
+        "-O3",
+        "-funroll-loops",
+        "-finline-functions",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-unreachable-code-loop-increment",
+    ],
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+
+    sanitize: {
+        integer_overflow: true,
+        misc_undefined: ["bounds"],
+        // Enable CFI if this is used as a shared library
+        // cfi: true,
+        blocklist: "libFLAC_blocklist.txt",
+    },
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    min_sdk_version: "29",
+}
diff --git a/src/libFLAC/CMakeLists.txt b/src/libFLAC/CMakeLists.txt
new file mode 100644
index 0000000..44a3519
--- /dev/null
+++ b/src/libFLAC/CMakeLists.txt
@@ -0,0 +1,125 @@
+option(WITH_ASM "Use any assembly optimization routines" ON)
+
+check_include_file("cpuid.h" HAVE_CPUID_H)
+check_include_file("sys/param.h" HAVE_SYS_PARAM_H)
+
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_function_exists(lround HAVE_LROUND)
+
+include(CheckCSourceCompiles)
+include(CheckCPUArch)
+
+check_cpu_arch_x64(FLAC__CPU_X86_64)
+if(NOT FLAC__CPU_X86_64)
+    check_cpu_arch_x86(FLAC__CPU_IA32)
+endif()
+
+if(FLAC__CPU_X86_64 OR FLAC__CPU_IA32)
+    set(FLAC__ALIGN_MALLOC_DATA 1)
+    option(WITH_AVX "Enable AVX, AVX2 optimizations" ON)
+endif()
+
+include(CheckLanguage)
+check_language(ASM_NASM)
+if(CMAKE_ASM_NASM_COMPILER)
+    enable_language(ASM_NASM)
+    add_definitions(-DFLAC__HAS_NASM)
+endif()
+
+if(NOT WITH_ASM)
+    add_definitions(-DFLAC__NO_ASM)
+endif()
+
+if(FLAC__CPU_IA32)
+    if(WITH_ASM AND CMAKE_ASM_NASM_COMPILER)
+        add_subdirectory(ia32)
+    endif()
+
+    option(WITH_SSE "Enable SSE2 optimizations" ON)
+    check_c_compiler_flag(-msse2 HAVE_MSSE2_FLAG)
+    if(WITH_SSE)
+        add_compile_options(
+            $<$<BOOL:${HAVE_MSSE2_FLAG}>:-msse2>
+            $<$<BOOL:${MSVC}>:/arch:SSE2>)
+    endif()
+endif()
+
+include_directories("include")
+
+add_library(FLAC
+    bitmath.c
+    bitreader.c
+    bitwriter.c
+    cpu.c
+    crc.c
+    fixed.c
+    fixed_intrin_sse2.c
+    fixed_intrin_ssse3.c
+    float.c
+    format.c
+    lpc.c
+    lpc_intrin_sse.c
+    lpc_intrin_sse2.c
+    lpc_intrin_sse41.c
+    lpc_intrin_avx2.c
+    lpc_intrin_vsx.c
+    md5.c
+    memory.c
+    metadata_iterators.c
+    metadata_object.c
+    stream_decoder.c
+    stream_encoder.c
+    stream_encoder_intrin_sse2.c
+    stream_encoder_intrin_ssse3.c
+    stream_encoder_intrin_avx2.c
+    stream_encoder_framing.c
+    window.c
+    $<$<BOOL:${WIN32}>:../../include/share/windows_unicode_filenames.h>
+    $<$<BOOL:${WIN32}>:windows_unicode_filenames.c>
+    $<$<BOOL:${OGG_FOUND}>:ogg_decoder_aspect.c>
+    $<$<BOOL:${OGG_FOUND}>:ogg_encoder_aspect.c>
+    $<$<BOOL:${OGG_FOUND}>:ogg_helper.c>
+    $<$<BOOL:${OGG_FOUND}>:ogg_mapping.c>)
+if(TARGET FLAC-asm)
+    target_sources(FLAC PRIVATE $<TARGET_OBJECTS:FLAC-asm>)
+endif()
+
+target_compile_definitions(FLAC
+    PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:FLAC_API_EXPORTS>
+    PUBLIC $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:FLAC__NO_DLL>)
+if(NOT WIN32)
+    target_compile_definitions(FLAC PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:FLAC__USE_VISIBILITY_ATTR>)
+endif()
+target_include_directories(FLAC INTERFACE
+    "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
+    "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
+target_link_libraries(FLAC PUBLIC $<$<BOOL:${HAVE_LROUND}>:m>)
+if(TARGET Ogg::ogg)
+    target_link_libraries(FLAC PUBLIC Ogg::ogg)
+endif()
+if(BUILD_SHARED_LIBS)
+    set_target_properties(FLAC PROPERTIES
+        VERSION 8.3.0
+        SOVERSION 8)
+    if(NOT WIN32)
+        set_target_properties(FLAC PROPERTIES C_VISIBILITY_PRESET hidden)
+    endif()
+endif()
+
+add_library(FLAC::FLAC ALIAS FLAC)
+
+
+install(TARGETS FLAC EXPORT targets
+    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
+    LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
+    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/")
+
+if(INSTALL_PKGCONFIG_MODULES)
+    set(prefix "${CMAKE_INSTALL_PREFIX}")
+    set(exec_prefix "${CMAKE_INSTALL_PREFIX}")
+    set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}")
+    set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
+    configure_file(flac.pc.in flac.pc @ONLY)
+    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/flac.pc"
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+endif()
diff --git a/libFLAC/MODULE_LICENSE_BSD_LIKE b/src/libFLAC/MODULE_LICENSE_BSD_LIKE
similarity index 100%
rename from libFLAC/MODULE_LICENSE_BSD_LIKE
rename to src/libFLAC/MODULE_LICENSE_BSD_LIKE
diff --git a/src/libFLAC/Makefile.am b/src/libFLAC/Makefile.am
new file mode 100644
index 0000000..468939d
--- /dev/null
+++ b/src/libFLAC/Makefile.am
@@ -0,0 +1,137 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+lib_LTLIBRARIES = libFLAC.la
+noinst_LTLIBRARIES = libFLAC-static.la
+if DEBUG
+DEBUGCFLAGS = -DFLAC__OVERFLOW_DETECT
+endif
+
+# FIXME: The following logic should be part of configure, not of Makefile.am
+
+if FLaC__CPU_PPC
+if FLaC__SYS_DARWIN
+CPUCFLAGS = -faltivec
+else
+CPUCFLAGS =
+if FLaC__USE_ALTIVEC
+CPUCFLAGS += -maltivec -mabi=altivec
+endif
+endif
+endif
+
+AM_CFLAGS = $(DEBUGCFLAGS) $(CPUCFLAGS) @OGG_CFLAGS@
+
+if FLaC__NO_ASM
+else
+if FLaC__CPU_IA32
+if FLaC__HAS_NASM
+ARCH_SUBDIRS = ia32
+LOCAL_EXTRA_LIBADD = ia32/libFLAC-asm.la
+endif
+endif
+endif
+
+libFLAC_la_LIBADD = $(LOCAL_EXTRA_LIBADD) @OGG_LIBS@ -lm
+
+SUBDIRS = $(ARCH_SUBDIRS) include .
+
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libFLAC.m4
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = flac.pc
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	flac.pc.in \
+	libFLAC_dynamic.vcproj \
+	libFLAC_dynamic.vcxproj \
+	libFLAC_dynamic.vcxproj.filters \
+	libFLAC_static.vcproj \
+	libFLAC_static.vcxproj \
+	libFLAC_static.vcxproj.filters \
+	libFLAC.m4 \
+	windows_unicode_filenames.c
+
+if OS_IS_WINDOWS
+windows_unicode_compat = windows_unicode_filenames.c
+endif
+
+if FLaC__HAS_OGG
+extra_ogg_sources = \
+	ogg_decoder_aspect.c \
+	ogg_encoder_aspect.c \
+	ogg_helper.c \
+	ogg_mapping.c
+endif
+
+# see 'http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning' for numbering convention
+libFLAC_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 11:0:3 $(LOCAL_EXTRA_LDFLAGS)
+
+libFLAC_sources = \
+	bitmath.c \
+	bitreader.c \
+	bitwriter.c \
+	cpu.c \
+	crc.c \
+	fixed.c \
+	fixed_intrin_sse2.c \
+	fixed_intrin_ssse3.c \
+	float.c \
+	format.c \
+	lpc.c \
+	lpc_intrin_sse.c \
+	lpc_intrin_sse2.c \
+	lpc_intrin_sse41.c \
+	lpc_intrin_avx2.c \
+	lpc_intrin_vsx.c \
+	md5.c \
+	memory.c \
+	metadata_iterators.c \
+	metadata_object.c \
+	stream_decoder.c \
+	stream_encoder.c \
+	stream_encoder_intrin_sse2.c \
+	stream_encoder_intrin_ssse3.c \
+	stream_encoder_intrin_avx2.c \
+	stream_encoder_framing.c \
+	window.c \
+	$(windows_unicode_compat) \
+	$(extra_ogg_sources)
+
+libFLAC_la_SOURCES = $(libFLAC_sources)
+
+# needed for test_libFLAC
+libFLAC_static_la_LIBADD = $(LOCAL_EXTRA_LIBADD)
+libFLAC_static_la_SOURCES = $(libFLAC_sources)
diff --git a/src/libFLAC/Makefile.lite b/src/libFLAC/Makefile.lite
new file mode 100644
index 0000000..aa3e175
--- /dev/null
+++ b/src/libFLAC/Makefile.lite
@@ -0,0 +1,110 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = $(OGG_LIBS) -lm
+endif
+
+ifeq ($(findstring Windows,$(OS)),Windows)
+    WIN_UNICODE_COMPAT = windows_unicode_filenames.c
+endif
+
+LIB_NAME = libFLAC
+ifeq ($(PROC),ppc)
+    DEFINES = -DFLAC__CPU_PPC -DFLAC__USE_ALTIVEC -DFLAC__ALIGN_MALLOC_DATA
+else
+ifeq ($(OS),Solaris)
+    DEFINES = -DFLAC__NO_ASM -DFLAC__ALIGN_MALLOC_DATA
+else
+ifeq ($(PROC),i386)
+    DEFINES = -DFLAC__CPU_IA32 -DFLAC__HAS_NASM -DFLAC__ALIGN_MALLOC_DATA
+else
+    DEFINES = -DFLAC__ALIGN_MALLOC_DATA
+endif
+endif
+endif
+INCLUDES = -I./include -I$(topdir)/include $(OGG_INCLUDES)
+DEBUG_CFLAGS = -DFLAC__OVERFLOW_DETECT
+
+ifeq ($(PROC),i386)
+SRCS_NASM = \
+	ia32/cpu_asm.nasm \
+	ia32/fixed_asm.nasm \
+	ia32/lpc_asm.nasm
+endif
+
+OGG_SRCS_C = \
+	ogg_decoder_aspect.c \
+	ogg_encoder_aspect.c \
+	ogg_helper.c \
+	ogg_mapping.c
+
+SRCS_C = \
+	bitmath.c \
+	bitreader.c \
+	bitwriter.c \
+	cpu.c \
+	crc.c \
+	fixed.c \
+	fixed_intrin_sse2.c \
+	fixed_intrin_ssse3.c \
+	float.c \
+	format.c \
+	lpc.c \
+	lpc_intrin_sse.c \
+	lpc_intrin_sse2.c \
+	lpc_intrin_sse41.c \
+	lpc_intrin_avx2.c \
+	md5.c \
+	memory.c \
+	metadata_iterators.c \
+	metadata_object.c \
+	stream_decoder.c \
+	stream_encoder.c \
+	stream_encoder_intrin_sse2.c \
+	stream_encoder_intrin_ssse3.c \
+	stream_encoder_intrin_avx2.c \
+	stream_encoder_framing.c \
+	window.c \
+	$(WIN_UNICODE_COMPAT) \
+	$(OGG_SRCS)
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/libFLAC/bitmath.c b/src/libFLAC/bitmath.c
new file mode 100644
index 0000000..32e31a7
--- /dev/null
+++ b/src/libFLAC/bitmath.c
@@ -0,0 +1,73 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/bitmath.h"
+
+/* An example of what FLAC__bitmath_silog2() computes:
+ *
+ * silog2(-10) = 5
+ * silog2(- 9) = 5
+ * silog2(- 8) = 4
+ * silog2(- 7) = 4
+ * silog2(- 6) = 4
+ * silog2(- 5) = 4
+ * silog2(- 4) = 3
+ * silog2(- 3) = 3
+ * silog2(- 2) = 2
+ * silog2(- 1) = 2
+ * silog2(  0) = 0
+ * silog2(  1) = 2
+ * silog2(  2) = 3
+ * silog2(  3) = 3
+ * silog2(  4) = 4
+ * silog2(  5) = 4
+ * silog2(  6) = 4
+ * silog2(  7) = 4
+ * silog2(  8) = 5
+ * silog2(  9) = 5
+ * silog2( 10) = 5
+ */
+uint32_t FLAC__bitmath_silog2(FLAC__int64 v)
+{
+	if(v == 0)
+		return 0;
+
+	if(v == -1)
+		return 2;
+
+	v = (v < 0) ? (-(v+1)) : v;
+	return FLAC__bitmath_ilog2_wide(v)+2;
+}
diff --git a/src/libFLAC/bitreader.c b/src/libFLAC/bitreader.c
new file mode 100644
index 0000000..79cb5cc
--- /dev/null
+++ b/src/libFLAC/bitreader.c
@@ -0,0 +1,1100 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  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 COUNT_ZERO_MSBS2 below to match */
+/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */
+/*           also, some sections currently only have fast versions for 4 or 8 bytes per word */
+
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 brword;
+#define FLAC__BYTES_PER_WORD 4		/* sizeof brword */
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (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
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) FLAC__clz_uint32(word)
+#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint32(word)
+
+#else
+
+typedef FLAC__uint64 brword;
+#define FLAC__BYTES_PER_WORD 8		/* sizeof brword */
+#define FLAC__BITS_PER_WORD 64
+#define FLAC__WORD_ALL_ONES ((FLAC__uint64)FLAC__U64L(0xffffffffffffffff))
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (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_64(x)
+#endif
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) FLAC__clz_uint64(word)
+#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint64(word)
+
+#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 uint32_t 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 */
+	brword *buffer;
+	uint32_t capacity; /* in words */
+	uint32_t words; /* # of completed words in buffer */
+	uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */
+	uint32_t consumed_words; /* #words ... */
+	uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+	uint32_t read_crc16; /* the running frame CRC */
+	uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */
+	uint32_t 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, brword word)
+{
+	register uint32_t crc = br->read_crc16;
+
+	for ( ; br->crc16_align < FLAC__BITS_PER_WORD ; br->crc16_align += 8) {
+		uint32_t shift = FLAC__BITS_PER_WORD - 8 - br->crc16_align ;
+		crc = FLAC__CRC16_UPDATE ((uint32_t) (shift < FLAC__BITS_PER_WORD ? (word >> shift) & 0xff : 0), crc);
+	}
+
+	br->read_crc16 = crc;
+	br->crc16_align = 0;
+}
+
+static inline void crc16_update_block_(FLAC__BitReader *br)
+{
+	if(br->consumed_words > br->crc16_offset && br->crc16_align)
+		crc16_update_word_(br, br->buffer[br->crc16_offset++]);
+
+	/* Prevent OOB read due to wrap-around. */
+	if (br->consumed_words > br->crc16_offset) {
+#if FLAC__BYTES_PER_WORD == 4
+		br->read_crc16 = FLAC__crc16_update_words32(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16);
+#elif FLAC__BYTES_PER_WORD == 8
+		br->read_crc16 = FLAC__crc16_update_words64(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16);
+#else
+		unsigned i;
+
+		for (i = br->crc16_offset; i < br->consumed_words; i++)
+			crc16_update_word_(br, br->buffer[i]);
+#endif
+	}
+
+	br->crc16_offset = 0;
+}
+
+static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br)
+{
+	uint32_t 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) {
+		crc16_update_block_(br); /* CRC consumed words */
+
+		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 brword 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 laid 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 + (uint32_t)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 + (uint32_t)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(brword) * 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)
+{
+	uint32_t 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, "%01d", br->buffer[i] & ((brword)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, "%01d", br->buffer[i] & ((brword)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 = (uint32_t)seed;
+	br->crc16_offset = br->consumed_words;
+	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);
+
+	/* CRC consumed words up to here */
+	crc16_update_block_(br);
+
+	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 brword tail = br->buffer[br->consumed_words];
+		for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8)
+			br->read_crc16 = FLAC__CRC16_UPDATE((uint32_t)((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 uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br)
+{
+	return 8 - (br->consumed_bits & 7);
+}
+
+inline uint32_t 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, uint32_t 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 uint32_t n = FLAC__BITS_PER_WORD - br->consumed_bits;
+			const brword word = br->buffer[br->consumed_words];
+			const brword mask = br->consumed_bits < FLAC__BITS_PER_WORD ? FLAC__WORD_ALL_ONES >> br->consumed_bits : 0;
+			if(bits < n) {
+				uint32_t shift = n - bits;
+				*val = shift < FLAC__BITS_PER_WORD ? (FLAC__uint32)((word & mask) >> shift) : 0; /* The result has <= 32 non-zero bits */
+				br->consumed_bits += bits;
+				return true;
+			}
+			/* (FLAC__BITS_PER_WORD - br->consumed_bits <= bits) ==> (FLAC__WORD_ALL_ONES >> br->consumed_bits) has no more than 'bits' non-zero bits */
+			*val = (FLAC__uint32)(word & mask);
+			bits -= n;
+			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 */
+				uint32_t shift = FLAC__BITS_PER_WORD - bits;
+				*val = bits < 32 ? *val << bits : 0;
+				*val |= shift < FLAC__BITS_PER_WORD ? (FLAC__uint32)(br->buffer[br->consumed_words] >> shift) : 0;
+				br->consumed_bits = bits;
+			}
+			return true;
+		}
+		else { /* br->consumed_bits == 0 */
+			const brword word = br->buffer[br->consumed_words];
+			if(bits < FLAC__BITS_PER_WORD) {
+				*val = (FLAC__uint32)(word >> (FLAC__BITS_PER_WORD-bits));
+				br->consumed_bits = bits;
+				return true;
+			}
+			/* at this point bits == FLAC__BITS_PER_WORD == 32; because of previous assertions, it can't be larger */
+			*val = (FLAC__uint32)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 = (FLAC__uint32)((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 = (FLAC__uint32)(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, uint32_t bits)
+{
+	FLAC__uint32 uval, mask;
+	/* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */
+	if (bits < 1 || ! FLAC__bitreader_read_raw_uint32(br, &uval, bits))
+		return false;
+	/* sign-extend *val assuming it is currently bits wide. */
+	/* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */
+	mask = bits >= 33 ? 0 : 1u << (bits - 1);
+	*val = (uval ^ mask) - mask;
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t 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, uint32_t 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 uint32_t n = br->consumed_bits & 7;
+		uint32_t 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, uint32_t 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, uint32_t 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 brword 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, uint32_t *val)
+#if 0 /* slow but readable version */
+{
+	uint32_t 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
+{
+	uint32_t 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... */
+			brword b = br->consumed_bits < FLAC__BITS_PER_WORD ? br->buffer[br->consumed_words] << br->consumed_bits : 0;
+			if(b) {
+				i = COUNT_ZERO_MSBS(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) */
+					br->consumed_words++;
+					br->consumed_bits = 0;
+				}
+				return true;
+			}
+			else {
+				*val += FLAC__BITS_PER_WORD - br->consumed_bits;
+				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 uint32_t end = br->bytes * 8;
+			brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits;
+			if(b) {
+				i = COUNT_ZERO_MSBS(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, uint32_t parameter)
+{
+	FLAC__uint32 lsbs = 0, msbs = 0;
+	uint32_t 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[], uint32_t nvals, uint32_t 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 */
+	uint32_t cwords, words, lsbs, msbs, x, y;
+	uint32_t ucbits; /* keep track of the number of unconsumed bits in word */
+	brword 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 = COUNT_ZERO_MSBS2(b);
+		if(x == FLAC__BITS_PER_WORD) {
+			x = ucbits;
+			do {
+				/* didn't find stop bit yet, have to keep going... */
+				cwords++;
+				if (cwords >= words)
+					goto incomplete_msbs;
+				b = br->buffer[cwords];
+				y = COUNT_ZERO_MSBS2(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 = (FLAC__uint32)(b >> (FLAC__BITS_PER_WORD - parameter)); /* parameter < 32, so we can cast to 32-bit uint32_t */
+		if(parameter <= ucbits) {
+			ucbits -= parameter;
+			b <<= parameter;
+		} else {
+			/* there are still bits left to read, they will all be in the next word */
+			cwords++;
+			if (cwords >= words)
+				goto incomplete_lsbs;
+			b = br->buffer[cwords];
+			ucbits += FLAC__BITS_PER_WORD - parameter;
+			x |= (FLAC__uint32)(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 = cwords < br->capacity ? br->buffer[cwords] << br->consumed_bits : 0;
+		} while(cwords >= words && val < end);
+	}
+
+	if(ucbits == 0 && cwords < words) {
+		/* don't leave the head word with no unconsumed bits */
+		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, uint32_t parameter)
+{
+	FLAC__uint32 lsbs = 0, msbs = 0;
+	uint32_t 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 {
+		uint32_t 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 uint32_t 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, uint32_t *val, uint32_t parameter)
+{
+	FLAC__uint32 lsbs, msbs = 0;
+	uint32_t 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 {
+		uint32_t 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, uint32_t *rawlen)
+{
+	FLAC__uint32 v = 0;
+	FLAC__uint32 x;
+	uint32_t 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, uint32_t *rawlen)
+{
+	FLAC__uint64 v = 0;
+	FLAC__uint32 x;
+	uint32_t 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 uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+extern uint32_t 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);
diff --git a/src/libFLAC/bitwriter.c b/src/libFLAC/bitwriter.c
new file mode 100644
index 0000000..6e86585
--- /dev/null
+++ b/src/libFLAC/bitwriter.c
@@ -0,0 +1,885 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 bwword is >= 32 bits wide */
+
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 bwword;
+#define FLAC__BYTES_PER_WORD 4		/* sizeof bwword */
+#define FLAC__BITS_PER_WORD 32
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (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
+
+#else
+
+typedef FLAC__uint64 bwword;
+#define FLAC__BYTES_PER_WORD 8		/* sizeof bwword */
+#define FLAC__BITS_PER_WORD 64
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (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_64(x)
+#endif
+
+#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 uint32_t FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(bwword); /* size in words */
+/* When growing, increment 4K at a time */
+static const uint32_t FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(bwword); /* 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 {
+	bwword *buffer;
+	bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */
+	uint32_t capacity; /* capacity of buffer in words */
+	uint32_t words; /* # of complete words in buffer */
+	uint32_t 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, uint32_t bits_to_add)
+{
+	uint32_t new_capacity;
+	bwword *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(bwword), /*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(bwword) * 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)
+{
+	uint32_t 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, "%01d", bw->buffer[i] & ((bwword)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, "%01d", bw->accum & ((bwword)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);
+}
+
+uint32_t 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, uint32_t bits)
+{
+	uint32_t 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;
+}
+
+static inline FLAC__bool FLAC__bitwriter_write_raw_uint32_nocheck(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits)
+{
+	register uint32_t 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);
+
+	if(bw == 0 || bw->buffer == 0)
+		return false;
+
+	if (bits > 32)
+		return false;
+
+	if(bits == 0)
+		return true;
+
+	FLAC__ASSERT((bits == 32) || (val>>bits == 0));
+
+	/* 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; /* unused top bits can contain garbage */
+	}
+	else { /* at this point bits == FLAC__BITS_PER_WORD == 32  and  bw->bits == 0 */
+		bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST((bwword)val);
+	}
+
+	return true;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits)
+{
+	/* check that unused bits are unset */
+	if((bits < 32) && (val>>bits != 0))
+		return false;
+
+	return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, bits);
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits)
+{
+	/* zero-out unused bits */
+	if(bits < 32)
+		val &= (~(0xffffffff << bits));
+
+	return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, bits);
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t 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_nocheck(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_nocheck(bw, val & 0xff, 8))
+		return false;
+	if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>8) & 0xff, 8))
+		return false;
+	if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>16) & 0xff, 8))
+		return false;
+	if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, val>>24, 8))
+		return false;
+
+	return true;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals)
+{
+	uint32_t i;
+
+	/* grow capacity upfront to prevent constant reallocation during writes */
+	if(bw->capacity <= bw->words + nvals / (FLAC__BITS_PER_WORD / 8) + 1 && !bitwriter_grow_(bw, nvals * 8))
+		return false;
+
+	/* 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_nocheck(bw, (FLAC__uint32)(vals[i]), 8))
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, uint32_t val)
+{
+	if(val < 32)
+		return FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, ++val);
+	else
+		return
+			FLAC__bitwriter_write_zeroes(bw, val) &&
+			FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, 1);
+}
+
+uint32_t FLAC__bitwriter_rice_bits(FLAC__int32 val, uint32_t parameter)
+{
+	FLAC__uint32 uval;
+
+	FLAC__ASSERT(parameter < 32);
+
+	/* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */
+	uval = val;
+	uval <<= 1;
+	uval ^= (val>>31);
+
+	return 1 + parameter + (uval >> parameter);
+}
+
+#if 0 /* UNUSED */
+uint32_t FLAC__bitwriter_golomb_bits_signed(int val, uint32_t parameter)
+{
+	uint32_t bits, msbs, uval;
+	uint32_t k;
+
+	FLAC__ASSERT(parameter > 0);
+
+	/* fold signed to uint32_t */
+	if(val < 0)
+		uval = (uint32_t)(((-(++val)) << 1) + 1);
+	else
+		uval = (uint32_t)(val << 1);
+
+	k = FLAC__bitmath_ilog2(parameter);
+	if(parameter == 1u<<k) {
+		FLAC__ASSERT(k <= 30);
+
+		msbs = uval >> k;
+		bits = 1 + k + msbs;
+	}
+	else {
+		uint32_t 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;
+}
+
+uint32_t FLAC__bitwriter_golomb_bits_unsigned(uint32_t uval, uint32_t parameter)
+{
+	uint32_t bits, msbs;
+	uint32_t 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 {
+		uint32_t 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, uint32_t parameter)
+{
+	uint32_t total_bits, interesting_bits, msbs;
+	FLAC__uint32 uval, pattern;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+	FLAC__ASSERT(parameter < 32);
+
+	/* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */
+	uval = val;
+	uval <<= 1;
+	uval ^= (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, uint32_t nvals, uint32_t parameter)
+{
+	const FLAC__uint32 mask1 = (FLAC__uint32)0xffffffff << parameter; /* we val|=mask1 to set the stop bit above it... */
+	const FLAC__uint32 mask2 = (FLAC__uint32)0xffffffff >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2 */
+	FLAC__uint32 uval;
+	uint32_t left;
+	const uint32_t lsbits = 1 + parameter;
+	uint32_t msbits, total_bits;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+	FLAC__ASSERT(parameter < 31);
+	/* 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 uint32_t; actual formula is: negative(v)? -2v-1 : 2v */
+		uval = *vals;
+		uval <<= 1;
+		uval ^= (*vals>>31);
+
+		msbits = uval >> parameter;
+		total_bits = lsbits + msbits;
+
+		if(bw->bits && bw->bits + total_bits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */
+			/* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */
+			bw->bits += total_bits;
+			uval |= mask1; /* set stop bit */
+			uval &= mask2; /* mask off unused top bits */
+			bw->accum <<= total_bits;
+			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 bwword */ && !bitwriter_grow_(bw, total_bits))
+				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; /* unused top bits can contain garbage */
+			}
+		}
+		vals++;
+		nvals--;
+	}
+	return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, uint32_t parameter)
+{
+	uint32_t total_bits, msbs, uval;
+	uint32_t k;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+	FLAC__ASSERT(parameter > 0);
+
+	/* fold signed to uint32_t */
+	if(val < 0)
+		uval = (uint32_t)(((-(++val)) << 1) + 1);
+	else
+		uval = (uint32_t)(val << 1);
+
+	k = FLAC__bitmath_ilog2(parameter);
+	if(parameter == 1u<<k) {
+		uint32_t 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 {
+		uint32_t 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, uint32_t uval, uint32_t parameter)
+{
+	uint32_t total_bits, msbs;
+	uint32_t k;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+	FLAC__ASSERT(parameter > 0);
+
+	k = FLAC__bitmath_ilog2(parameter);
+	if(parameter == 1u<<k) {
+		uint32_t 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 {
+		uint32_t 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);
+
+	if((val & 0x80000000) != 0) /* this version only handles 31 bits */
+		return false;
+
+	if(val < 0x80) {
+		return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, 8);
+	}
+	else if(val < 0x800) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (val>>6), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
+	}
+	else if(val < 0x10000) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (val>>12), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
+	}
+	else if(val < 0x200000) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (val>>18), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
+	}
+	else if(val < 0x4000000) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (val>>24), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
+	}
+	else {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (val>>30), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>24)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(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);
+
+	if((val & FLAC__U64L(0xFFFFFFF000000000)) != 0) /* this version only handles 36 bits */
+		return false;
+
+	if(val < 0x80) {
+		return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, 8);
+	}
+	else if(val < 0x800) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (FLAC__uint32)(val>>6), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x10000) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (FLAC__uint32)(val>>12), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x200000) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (FLAC__uint32)(val>>18), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x4000000) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (FLAC__uint32)(val>>24), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x80000000) {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (FLAC__uint32)(val>>30), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else {
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFE, 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32_nocheck(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, uint32_t bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t 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[], uint32_t nvals);
diff --git a/src/libFLAC/cpu.c b/src/libFLAC/cpu.c
new file mode 100644
index 0000000..8b92f4c
--- /dev/null
+++ b/src/libFLAC/cpu.c
@@ -0,0 +1,305 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+#include "share/compat.h"
+#include <stdlib.h>
+#include <string.h>
+
+#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
+
+#ifndef NDEBUG
+#include <stdio.h>
+#define dfprintf fprintf
+#else
+/* This is bad practice, it should be a static void empty function */
+#define dfprintf(file, format, ...)
+#endif
+
+#if defined FLAC__CPU_PPC
+#if defined(__linux__) || (defined(__FreeBSD__) && (__FreeBSD__ >= 12))
+#include <sys/auxv.h>
+#endif
+#endif
+
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
+
+/* these are flags in EDX of CPUID AX=00000001 */
+static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV    = 0x00008000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX     = 0x00800000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE     = 0x02000000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2    = 0x04000000;
+
+/* these are flags in ECX of CPUID AX=00000001 */
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3    = 0x00000001;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3   = 0x00000200;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41   = 0x00080000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42   = 0x00100000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE = 0x08000000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX     = 0x10000000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA     = 0x00001000;
+
+/* these are flags in EBX of CPUID AX=00000007 */
+static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2    = 0x00000020;
+
+static uint32_t
+cpu_xgetbv_x86(void)
+{
+#if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED
+	return (uint32_t)_xgetbv(0);
+#elif defined __GNUC__
+	uint32_t lo, hi;
+	__asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
+	return lo;
+#else
+	return 0;
+#endif
+}
+
+static uint32_t
+cpu_have_cpuid(void)
+{
+#if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0)
+	/* target CPU does have CPUID instruction */
+	return 1;
+#elif defined FLAC__HAS_NASM
+	return FLAC__cpu_have_cpuid_asm_ia32();
+#elif defined __GNUC__ && defined HAVE_CPUID_H
+	if (__get_cpuid_max(0, 0) != 0)
+		return 1;
+	else
+		return 0;
+#elif defined _MSC_VER
+	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;
+#else
+	return 0;
+#endif
+}
+
+static void
+cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
+{
+#if defined _MSC_VER
+	int cpuinfo[4];
+	int ext = level & 0x80000000;
+	__cpuid(cpuinfo, ext);
+	if ((uint32_t)cpuinfo[0] >= level) {
+#if 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];
+		return;
+	}
+#elif defined __GNUC__ && defined HAVE_CPUID_H
+	FLAC__uint32 ext = level & 0x80000000;
+	__cpuid(ext, *eax, *ebx, *ecx, *edx);
+	if (*eax >= level) {
+		__cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
+		return;
+	}
+#elif defined FLAC__HAS_NASM && defined FLAC__CPU_IA32
+	FLAC__cpu_info_asm_ia32(level, eax, ebx, ecx, edx);
+	return;
+#endif
+	*eax = *ebx = *ecx = *edx = 0;
+}
+
+#endif
+
+static void
+x86_cpu_info (FLAC__CPUInfo *info)
+{
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
+	FLAC__bool x86_osxsave = false;
+	FLAC__bool os_avx = false;
+	FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
+
+	info->use_asm = true; /* we assume a minimum of 80386 */
+	if (!cpu_have_cpuid())
+		return;
+
+	cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+	info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
+	cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+
+	info->x86.cmov  = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false;
+	info->x86.mmx   = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX  ) ? true : false;
+	info->x86.sse   = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE  ) ? true : false;
+	info->x86.sse2  = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false;
+	info->x86.sse3  = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false;
+	info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false;
+	info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false;
+	info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false;
+
+	if (FLAC__AVX_SUPPORTED) {
+		x86_osxsave     = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false;
+		info->x86.avx   = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX    ) ? true : false;
+		info->x86.fma   = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA    ) ? true : false;
+		cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+		info->x86.avx2  = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2   ) ? true : false;
+	}
+
+#if defined FLAC__CPU_IA32
+	dfprintf(stderr, "CPU info (IA-32):\n");
+#else
+	dfprintf(stderr, "CPU info (x86-64):\n");
+#endif
+	dfprintf(stderr, "  CMOV ....... %c\n", info->x86.cmov    ? 'Y' : 'n');
+	dfprintf(stderr, "  MMX ........ %c\n", info->x86.mmx     ? 'Y' : 'n');
+	dfprintf(stderr, "  SSE ........ %c\n", info->x86.sse     ? 'Y' : 'n');
+	dfprintf(stderr, "  SSE2 ....... %c\n", info->x86.sse2    ? 'Y' : 'n');
+	dfprintf(stderr, "  SSE3 ....... %c\n", info->x86.sse3    ? 'Y' : 'n');
+	dfprintf(stderr, "  SSSE3 ...... %c\n", info->x86.ssse3   ? 'Y' : 'n');
+	dfprintf(stderr, "  SSE41 ...... %c\n", info->x86.sse41   ? 'Y' : 'n');
+	dfprintf(stderr, "  SSE42 ...... %c\n", info->x86.sse42   ? 'Y' : 'n');
+
+	if (FLAC__AVX_SUPPORTED) {
+		dfprintf(stderr, "  AVX ........ %c\n", info->x86.avx     ? 'Y' : 'n');
+		dfprintf(stderr, "  FMA ........ %c\n", info->x86.fma     ? 'Y' : 'n');
+		dfprintf(stderr, "  AVX2 ....... %c\n", info->x86.avx2    ? 'Y' : 'n');
+	}
+
+	/*
+	 * now have to check for OS support of AVX instructions
+	 */
+	if (FLAC__AVX_SUPPORTED && info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) {
+		os_avx = true;
+	}
+	if (os_avx) {
+		dfprintf(stderr, "  AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
+	}
+	if (!os_avx) {
+		/* no OS AVX support */
+		info->x86.avx     = false;
+		info->x86.avx2    = false;
+		info->x86.fma     = false;
+	}
+#else
+	info->use_asm = false;
+#endif
+}
+
+static void
+ppc_cpu_info (FLAC__CPUInfo *info)
+{
+#if defined FLAC__CPU_PPC
+#ifndef PPC_FEATURE2_ARCH_3_00
+#define PPC_FEATURE2_ARCH_3_00		0x00800000
+#endif
+
+#ifndef PPC_FEATURE2_ARCH_2_07
+#define PPC_FEATURE2_ARCH_2_07		0x80000000
+#endif
+
+#ifdef __linux__
+	if (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) {
+		info->ppc.arch_3_00 = true;
+	} else if (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) {
+		info->ppc.arch_2_07 = true;
+	}
+#elif defined(__FreeBSD__) && (__FreeBSD__ >= 12)
+	long hwcaps;
+	/* elf_aux_info() appeared in FreeBSD 12.0 */
+	elf_aux_info(AT_HWCAP2, &hwcaps, sizeof(hwcaps));
+	if (hwcaps & PPC_FEATURE2_ARCH_3_00) {
+		info->ppc.arch_3_00 = true;
+	} else if (hwcaps & PPC_FEATURE2_ARCH_2_07) {
+		info->ppc.arch_2_07 = true;
+	}
+#elif defined(__APPLE__)
+	/* no Mac OS X version supports CPU with Power AVI v2.07 or better */
+	info->ppc.arch_2_07 = false;
+	info->ppc.arch_3_00 = false;
+#else
+#error Unsupported platform! Please add support for reading ppc hwcaps.
+#endif
+
+#else
+	info->ppc.arch_2_07 = false;
+	info->ppc.arch_3_00 = false;
+#endif
+}
+
+void FLAC__cpu_info (FLAC__CPUInfo *info)
+{
+	memset(info, 0, sizeof(*info));
+
+#ifdef FLAC__CPU_IA32
+	info->type = FLAC__CPUINFO_TYPE_IA32;
+#elif defined FLAC__CPU_X86_64
+	info->type = FLAC__CPUINFO_TYPE_X86_64;
+#elif defined FLAC__CPU_PPC
+	info->type = FLAC__CPUINFO_TYPE_PPC;
+#else
+	info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
+#endif
+
+	switch (info->type) {
+	case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */
+	case FLAC__CPUINFO_TYPE_X86_64:
+		x86_cpu_info (info);
+		break;
+	case FLAC__CPUINFO_TYPE_PPC:
+		ppc_cpu_info (info);
+		break;
+	default:
+		info->use_asm = false;
+		break;
+	}
+}
diff --git a/src/libFLAC/crc.c b/src/libFLAC/crc.c
new file mode 100644
index 0000000..faa3496
--- /dev/null
+++ b/src/libFLAC/crc.c
@@ -0,0 +1,436 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  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/crc.h"
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+
+FLAC__uint8 const FLAC__crc8_table[256] = {
+	0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+	0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+	0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+	0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+	0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+	0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+	0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+	0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+	0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+	0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+	0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+	0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+	0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+	0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+	0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+	0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+	0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+	0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+	0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+	0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+	0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+	0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+	0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+	0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+	0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+	0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+	0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+	0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+	0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+	0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+	0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+	0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
+
+FLAC__uint16 const FLAC__crc16_table[8][256] = {
+  { 0x0000,  0x8005,  0x800f,  0x000a,  0x801b,  0x001e,  0x0014,  0x8011,
+	0x8033,  0x0036,  0x003c,  0x8039,  0x0028,  0x802d,  0x8027,  0x0022,
+	0x8063,  0x0066,  0x006c,  0x8069,  0x0078,  0x807d,  0x8077,  0x0072,
+	0x0050,  0x8055,  0x805f,  0x005a,  0x804b,  0x004e,  0x0044,  0x8041,
+	0x80c3,  0x00c6,  0x00cc,  0x80c9,  0x00d8,  0x80dd,  0x80d7,  0x00d2,
+	0x00f0,  0x80f5,  0x80ff,  0x00fa,  0x80eb,  0x00ee,  0x00e4,  0x80e1,
+	0x00a0,  0x80a5,  0x80af,  0x00aa,  0x80bb,  0x00be,  0x00b4,  0x80b1,
+	0x8093,  0x0096,  0x009c,  0x8099,  0x0088,  0x808d,  0x8087,  0x0082,
+	0x8183,  0x0186,  0x018c,  0x8189,  0x0198,  0x819d,  0x8197,  0x0192,
+	0x01b0,  0x81b5,  0x81bf,  0x01ba,  0x81ab,  0x01ae,  0x01a4,  0x81a1,
+	0x01e0,  0x81e5,  0x81ef,  0x01ea,  0x81fb,  0x01fe,  0x01f4,  0x81f1,
+	0x81d3,  0x01d6,  0x01dc,  0x81d9,  0x01c8,  0x81cd,  0x81c7,  0x01c2,
+	0x0140,  0x8145,  0x814f,  0x014a,  0x815b,  0x015e,  0x0154,  0x8151,
+	0x8173,  0x0176,  0x017c,  0x8179,  0x0168,  0x816d,  0x8167,  0x0162,
+	0x8123,  0x0126,  0x012c,  0x8129,  0x0138,  0x813d,  0x8137,  0x0132,
+	0x0110,  0x8115,  0x811f,  0x011a,  0x810b,  0x010e,  0x0104,  0x8101,
+	0x8303,  0x0306,  0x030c,  0x8309,  0x0318,  0x831d,  0x8317,  0x0312,
+	0x0330,  0x8335,  0x833f,  0x033a,  0x832b,  0x032e,  0x0324,  0x8321,
+	0x0360,  0x8365,  0x836f,  0x036a,  0x837b,  0x037e,  0x0374,  0x8371,
+	0x8353,  0x0356,  0x035c,  0x8359,  0x0348,  0x834d,  0x8347,  0x0342,
+	0x03c0,  0x83c5,  0x83cf,  0x03ca,  0x83db,  0x03de,  0x03d4,  0x83d1,
+	0x83f3,  0x03f6,  0x03fc,  0x83f9,  0x03e8,  0x83ed,  0x83e7,  0x03e2,
+	0x83a3,  0x03a6,  0x03ac,  0x83a9,  0x03b8,  0x83bd,  0x83b7,  0x03b2,
+	0x0390,  0x8395,  0x839f,  0x039a,  0x838b,  0x038e,  0x0384,  0x8381,
+	0x0280,  0x8285,  0x828f,  0x028a,  0x829b,  0x029e,  0x0294,  0x8291,
+	0x82b3,  0x02b6,  0x02bc,  0x82b9,  0x02a8,  0x82ad,  0x82a7,  0x02a2,
+	0x82e3,  0x02e6,  0x02ec,  0x82e9,  0x02f8,  0x82fd,  0x82f7,  0x02f2,
+	0x02d0,  0x82d5,  0x82df,  0x02da,  0x82cb,  0x02ce,  0x02c4,  0x82c1,
+	0x8243,  0x0246,  0x024c,  0x8249,  0x0258,  0x825d,  0x8257,  0x0252,
+	0x0270,  0x8275,  0x827f,  0x027a,  0x826b,  0x026e,  0x0264,  0x8261,
+	0x0220,  0x8225,  0x822f,  0x022a,  0x823b,  0x023e,  0x0234,  0x8231,
+	0x8213,  0x0216,  0x021c,  0x8219,  0x0208,  0x820d,  0x8207,  0x0202 },
+
+  { 0x0000,  0x8603,  0x8c03,  0x0a00,  0x9803,  0x1e00,  0x1400,  0x9203,
+	0xb003,  0x3600,  0x3c00,  0xba03,  0x2800,  0xae03,  0xa403,  0x2200,
+	0xe003,  0x6600,  0x6c00,  0xea03,  0x7800,  0xfe03,  0xf403,  0x7200,
+	0x5000,  0xd603,  0xdc03,  0x5a00,  0xc803,  0x4e00,  0x4400,  0xc203,
+	0x4003,  0xc600,  0xcc00,  0x4a03,  0xd800,  0x5e03,  0x5403,  0xd200,
+	0xf000,  0x7603,  0x7c03,  0xfa00,  0x6803,  0xee00,  0xe400,  0x6203,
+	0xa000,  0x2603,  0x2c03,  0xaa00,  0x3803,  0xbe00,  0xb400,  0x3203,
+	0x1003,  0x9600,  0x9c00,  0x1a03,  0x8800,  0x0e03,  0x0403,  0x8200,
+	0x8006,  0x0605,  0x0c05,  0x8a06,  0x1805,  0x9e06,  0x9406,  0x1205,
+	0x3005,  0xb606,  0xbc06,  0x3a05,  0xa806,  0x2e05,  0x2405,  0xa206,
+	0x6005,  0xe606,  0xec06,  0x6a05,  0xf806,  0x7e05,  0x7405,  0xf206,
+	0xd006,  0x5605,  0x5c05,  0xda06,  0x4805,  0xce06,  0xc406,  0x4205,
+	0xc005,  0x4606,  0x4c06,  0xca05,  0x5806,  0xde05,  0xd405,  0x5206,
+	0x7006,  0xf605,  0xfc05,  0x7a06,  0xe805,  0x6e06,  0x6406,  0xe205,
+	0x2006,  0xa605,  0xac05,  0x2a06,  0xb805,  0x3e06,  0x3406,  0xb205,
+	0x9005,  0x1606,  0x1c06,  0x9a05,  0x0806,  0x8e05,  0x8405,  0x0206,
+	0x8009,  0x060a,  0x0c0a,  0x8a09,  0x180a,  0x9e09,  0x9409,  0x120a,
+	0x300a,  0xb609,  0xbc09,  0x3a0a,  0xa809,  0x2e0a,  0x240a,  0xa209,
+	0x600a,  0xe609,  0xec09,  0x6a0a,  0xf809,  0x7e0a,  0x740a,  0xf209,
+	0xd009,  0x560a,  0x5c0a,  0xda09,  0x480a,  0xce09,  0xc409,  0x420a,
+	0xc00a,  0x4609,  0x4c09,  0xca0a,  0x5809,  0xde0a,  0xd40a,  0x5209,
+	0x7009,  0xf60a,  0xfc0a,  0x7a09,  0xe80a,  0x6e09,  0x6409,  0xe20a,
+	0x2009,  0xa60a,  0xac0a,  0x2a09,  0xb80a,  0x3e09,  0x3409,  0xb20a,
+	0x900a,  0x1609,  0x1c09,  0x9a0a,  0x0809,  0x8e0a,  0x840a,  0x0209,
+	0x000f,  0x860c,  0x8c0c,  0x0a0f,  0x980c,  0x1e0f,  0x140f,  0x920c,
+	0xb00c,  0x360f,  0x3c0f,  0xba0c,  0x280f,  0xae0c,  0xa40c,  0x220f,
+	0xe00c,  0x660f,  0x6c0f,  0xea0c,  0x780f,  0xfe0c,  0xf40c,  0x720f,
+	0x500f,  0xd60c,  0xdc0c,  0x5a0f,  0xc80c,  0x4e0f,  0x440f,  0xc20c,
+	0x400c,  0xc60f,  0xcc0f,  0x4a0c,  0xd80f,  0x5e0c,  0x540c,  0xd20f,
+	0xf00f,  0x760c,  0x7c0c,  0xfa0f,  0x680c,  0xee0f,  0xe40f,  0x620c,
+	0xa00f,  0x260c,  0x2c0c,  0xaa0f,  0x380c,  0xbe0f,  0xb40f,  0x320c,
+	0x100c,  0x960f,  0x9c0f,  0x1a0c,  0x880f,  0x0e0c,  0x040c,  0x820f },
+
+  { 0x0000,  0x8017,  0x802b,  0x003c,  0x8053,  0x0044,  0x0078,  0x806f,
+	0x80a3,  0x00b4,  0x0088,  0x809f,  0x00f0,  0x80e7,  0x80db,  0x00cc,
+	0x8143,  0x0154,  0x0168,  0x817f,  0x0110,  0x8107,  0x813b,  0x012c,
+	0x01e0,  0x81f7,  0x81cb,  0x01dc,  0x81b3,  0x01a4,  0x0198,  0x818f,
+	0x8283,  0x0294,  0x02a8,  0x82bf,  0x02d0,  0x82c7,  0x82fb,  0x02ec,
+	0x0220,  0x8237,  0x820b,  0x021c,  0x8273,  0x0264,  0x0258,  0x824f,
+	0x03c0,  0x83d7,  0x83eb,  0x03fc,  0x8393,  0x0384,  0x03b8,  0x83af,
+	0x8363,  0x0374,  0x0348,  0x835f,  0x0330,  0x8327,  0x831b,  0x030c,
+	0x8503,  0x0514,  0x0528,  0x853f,  0x0550,  0x8547,  0x857b,  0x056c,
+	0x05a0,  0x85b7,  0x858b,  0x059c,  0x85f3,  0x05e4,  0x05d8,  0x85cf,
+	0x0440,  0x8457,  0x846b,  0x047c,  0x8413,  0x0404,  0x0438,  0x842f,
+	0x84e3,  0x04f4,  0x04c8,  0x84df,  0x04b0,  0x84a7,  0x849b,  0x048c,
+	0x0780,  0x8797,  0x87ab,  0x07bc,  0x87d3,  0x07c4,  0x07f8,  0x87ef,
+	0x8723,  0x0734,  0x0708,  0x871f,  0x0770,  0x8767,  0x875b,  0x074c,
+	0x86c3,  0x06d4,  0x06e8,  0x86ff,  0x0690,  0x8687,  0x86bb,  0x06ac,
+	0x0660,  0x8677,  0x864b,  0x065c,  0x8633,  0x0624,  0x0618,  0x860f,
+	0x8a03,  0x0a14,  0x0a28,  0x8a3f,  0x0a50,  0x8a47,  0x8a7b,  0x0a6c,
+	0x0aa0,  0x8ab7,  0x8a8b,  0x0a9c,  0x8af3,  0x0ae4,  0x0ad8,  0x8acf,
+	0x0b40,  0x8b57,  0x8b6b,  0x0b7c,  0x8b13,  0x0b04,  0x0b38,  0x8b2f,
+	0x8be3,  0x0bf4,  0x0bc8,  0x8bdf,  0x0bb0,  0x8ba7,  0x8b9b,  0x0b8c,
+	0x0880,  0x8897,  0x88ab,  0x08bc,  0x88d3,  0x08c4,  0x08f8,  0x88ef,
+	0x8823,  0x0834,  0x0808,  0x881f,  0x0870,  0x8867,  0x885b,  0x084c,
+	0x89c3,  0x09d4,  0x09e8,  0x89ff,  0x0990,  0x8987,  0x89bb,  0x09ac,
+	0x0960,  0x8977,  0x894b,  0x095c,  0x8933,  0x0924,  0x0918,  0x890f,
+	0x0f00,  0x8f17,  0x8f2b,  0x0f3c,  0x8f53,  0x0f44,  0x0f78,  0x8f6f,
+	0x8fa3,  0x0fb4,  0x0f88,  0x8f9f,  0x0ff0,  0x8fe7,  0x8fdb,  0x0fcc,
+	0x8e43,  0x0e54,  0x0e68,  0x8e7f,  0x0e10,  0x8e07,  0x8e3b,  0x0e2c,
+	0x0ee0,  0x8ef7,  0x8ecb,  0x0edc,  0x8eb3,  0x0ea4,  0x0e98,  0x8e8f,
+	0x8d83,  0x0d94,  0x0da8,  0x8dbf,  0x0dd0,  0x8dc7,  0x8dfb,  0x0dec,
+	0x0d20,  0x8d37,  0x8d0b,  0x0d1c,  0x8d73,  0x0d64,  0x0d58,  0x8d4f,
+	0x0cc0,  0x8cd7,  0x8ceb,  0x0cfc,  0x8c93,  0x0c84,  0x0cb8,  0x8caf,
+	0x8c63,  0x0c74,  0x0c48,  0x8c5f,  0x0c30,  0x8c27,  0x8c1b,  0x0c0c },
+
+  { 0x0000,  0x9403,  0xa803,  0x3c00,  0xd003,  0x4400,  0x7800,  0xec03,
+	0x2003,  0xb400,  0x8800,  0x1c03,  0xf000,  0x6403,  0x5803,  0xcc00,
+	0x4006,  0xd405,  0xe805,  0x7c06,  0x9005,  0x0406,  0x3806,  0xac05,
+	0x6005,  0xf406,  0xc806,  0x5c05,  0xb006,  0x2405,  0x1805,  0x8c06,
+	0x800c,  0x140f,  0x280f,  0xbc0c,  0x500f,  0xc40c,  0xf80c,  0x6c0f,
+	0xa00f,  0x340c,  0x080c,  0x9c0f,  0x700c,  0xe40f,  0xd80f,  0x4c0c,
+	0xc00a,  0x5409,  0x6809,  0xfc0a,  0x1009,  0x840a,  0xb80a,  0x2c09,
+	0xe009,  0x740a,  0x480a,  0xdc09,  0x300a,  0xa409,  0x9809,  0x0c0a,
+	0x801d,  0x141e,  0x281e,  0xbc1d,  0x501e,  0xc41d,  0xf81d,  0x6c1e,
+	0xa01e,  0x341d,  0x081d,  0x9c1e,  0x701d,  0xe41e,  0xd81e,  0x4c1d,
+	0xc01b,  0x5418,  0x6818,  0xfc1b,  0x1018,  0x841b,  0xb81b,  0x2c18,
+	0xe018,  0x741b,  0x481b,  0xdc18,  0x301b,  0xa418,  0x9818,  0x0c1b,
+	0x0011,  0x9412,  0xa812,  0x3c11,  0xd012,  0x4411,  0x7811,  0xec12,
+	0x2012,  0xb411,  0x8811,  0x1c12,  0xf011,  0x6412,  0x5812,  0xcc11,
+	0x4017,  0xd414,  0xe814,  0x7c17,  0x9014,  0x0417,  0x3817,  0xac14,
+	0x6014,  0xf417,  0xc817,  0x5c14,  0xb017,  0x2414,  0x1814,  0x8c17,
+	0x803f,  0x143c,  0x283c,  0xbc3f,  0x503c,  0xc43f,  0xf83f,  0x6c3c,
+	0xa03c,  0x343f,  0x083f,  0x9c3c,  0x703f,  0xe43c,  0xd83c,  0x4c3f,
+	0xc039,  0x543a,  0x683a,  0xfc39,  0x103a,  0x8439,  0xb839,  0x2c3a,
+	0xe03a,  0x7439,  0x4839,  0xdc3a,  0x3039,  0xa43a,  0x983a,  0x0c39,
+	0x0033,  0x9430,  0xa830,  0x3c33,  0xd030,  0x4433,  0x7833,  0xec30,
+	0x2030,  0xb433,  0x8833,  0x1c30,  0xf033,  0x6430,  0x5830,  0xcc33,
+	0x4035,  0xd436,  0xe836,  0x7c35,  0x9036,  0x0435,  0x3835,  0xac36,
+	0x6036,  0xf435,  0xc835,  0x5c36,  0xb035,  0x2436,  0x1836,  0x8c35,
+	0x0022,  0x9421,  0xa821,  0x3c22,  0xd021,  0x4422,  0x7822,  0xec21,
+	0x2021,  0xb422,  0x8822,  0x1c21,  0xf022,  0x6421,  0x5821,  0xcc22,
+	0x4024,  0xd427,  0xe827,  0x7c24,  0x9027,  0x0424,  0x3824,  0xac27,
+	0x6027,  0xf424,  0xc824,  0x5c27,  0xb024,  0x2427,  0x1827,  0x8c24,
+	0x802e,  0x142d,  0x282d,  0xbc2e,  0x502d,  0xc42e,  0xf82e,  0x6c2d,
+	0xa02d,  0x342e,  0x082e,  0x9c2d,  0x702e,  0xe42d,  0xd82d,  0x4c2e,
+	0xc028,  0x542b,  0x682b,  0xfc28,  0x102b,  0x8428,  0xb828,  0x2c2b,
+	0xe02b,  0x7428,  0x4828,  0xdc2b,  0x3028,  0xa42b,  0x982b,  0x0c28 },
+
+  { 0x0000,  0x807b,  0x80f3,  0x0088,  0x81e3,  0x0198,  0x0110,  0x816b,
+	0x83c3,  0x03b8,  0x0330,  0x834b,  0x0220,  0x825b,  0x82d3,  0x02a8,
+	0x8783,  0x07f8,  0x0770,  0x870b,  0x0660,  0x861b,  0x8693,  0x06e8,
+	0x0440,  0x843b,  0x84b3,  0x04c8,  0x85a3,  0x05d8,  0x0550,  0x852b,
+	0x8f03,  0x0f78,  0x0ff0,  0x8f8b,  0x0ee0,  0x8e9b,  0x8e13,  0x0e68,
+	0x0cc0,  0x8cbb,  0x8c33,  0x0c48,  0x8d23,  0x0d58,  0x0dd0,  0x8dab,
+	0x0880,  0x88fb,  0x8873,  0x0808,  0x8963,  0x0918,  0x0990,  0x89eb,
+	0x8b43,  0x0b38,  0x0bb0,  0x8bcb,  0x0aa0,  0x8adb,  0x8a53,  0x0a28,
+	0x9e03,  0x1e78,  0x1ef0,  0x9e8b,  0x1fe0,  0x9f9b,  0x9f13,  0x1f68,
+	0x1dc0,  0x9dbb,  0x9d33,  0x1d48,  0x9c23,  0x1c58,  0x1cd0,  0x9cab,
+	0x1980,  0x99fb,  0x9973,  0x1908,  0x9863,  0x1818,  0x1890,  0x98eb,
+	0x9a43,  0x1a38,  0x1ab0,  0x9acb,  0x1ba0,  0x9bdb,  0x9b53,  0x1b28,
+	0x1100,  0x917b,  0x91f3,  0x1188,  0x90e3,  0x1098,  0x1010,  0x906b,
+	0x92c3,  0x12b8,  0x1230,  0x924b,  0x1320,  0x935b,  0x93d3,  0x13a8,
+	0x9683,  0x16f8,  0x1670,  0x960b,  0x1760,  0x971b,  0x9793,  0x17e8,
+	0x1540,  0x953b,  0x95b3,  0x15c8,  0x94a3,  0x14d8,  0x1450,  0x942b,
+	0xbc03,  0x3c78,  0x3cf0,  0xbc8b,  0x3de0,  0xbd9b,  0xbd13,  0x3d68,
+	0x3fc0,  0xbfbb,  0xbf33,  0x3f48,  0xbe23,  0x3e58,  0x3ed0,  0xbeab,
+	0x3b80,  0xbbfb,  0xbb73,  0x3b08,  0xba63,  0x3a18,  0x3a90,  0xbaeb,
+	0xb843,  0x3838,  0x38b0,  0xb8cb,  0x39a0,  0xb9db,  0xb953,  0x3928,
+	0x3300,  0xb37b,  0xb3f3,  0x3388,  0xb2e3,  0x3298,  0x3210,  0xb26b,
+	0xb0c3,  0x30b8,  0x3030,  0xb04b,  0x3120,  0xb15b,  0xb1d3,  0x31a8,
+	0xb483,  0x34f8,  0x3470,  0xb40b,  0x3560,  0xb51b,  0xb593,  0x35e8,
+	0x3740,  0xb73b,  0xb7b3,  0x37c8,  0xb6a3,  0x36d8,  0x3650,  0xb62b,
+	0x2200,  0xa27b,  0xa2f3,  0x2288,  0xa3e3,  0x2398,  0x2310,  0xa36b,
+	0xa1c3,  0x21b8,  0x2130,  0xa14b,  0x2020,  0xa05b,  0xa0d3,  0x20a8,
+	0xa583,  0x25f8,  0x2570,  0xa50b,  0x2460,  0xa41b,  0xa493,  0x24e8,
+	0x2640,  0xa63b,  0xa6b3,  0x26c8,  0xa7a3,  0x27d8,  0x2750,  0xa72b,
+	0xad03,  0x2d78,  0x2df0,  0xad8b,  0x2ce0,  0xac9b,  0xac13,  0x2c68,
+	0x2ec0,  0xaebb,  0xae33,  0x2e48,  0xaf23,  0x2f58,  0x2fd0,  0xafab,
+	0x2a80,  0xaafb,  0xaa73,  0x2a08,  0xab63,  0x2b18,  0x2b90,  0xabeb,
+	0xa943,  0x2938,  0x29b0,  0xa9cb,  0x28a0,  0xa8db,  0xa853,  0x2828 },
+
+  { 0x0000,  0xf803,  0x7003,  0x8800,  0xe006,  0x1805,  0x9005,  0x6806,
+	0x4009,  0xb80a,  0x300a,  0xc809,  0xa00f,  0x580c,  0xd00c,  0x280f,
+	0x8012,  0x7811,  0xf011,  0x0812,  0x6014,  0x9817,  0x1017,  0xe814,
+	0xc01b,  0x3818,  0xb018,  0x481b,  0x201d,  0xd81e,  0x501e,  0xa81d,
+	0x8021,  0x7822,  0xf022,  0x0821,  0x6027,  0x9824,  0x1024,  0xe827,
+	0xc028,  0x382b,  0xb02b,  0x4828,  0x202e,  0xd82d,  0x502d,  0xa82e,
+	0x0033,  0xf830,  0x7030,  0x8833,  0xe035,  0x1836,  0x9036,  0x6835,
+	0x403a,  0xb839,  0x3039,  0xc83a,  0xa03c,  0x583f,  0xd03f,  0x283c,
+	0x8047,  0x7844,  0xf044,  0x0847,  0x6041,  0x9842,  0x1042,  0xe841,
+	0xc04e,  0x384d,  0xb04d,  0x484e,  0x2048,  0xd84b,  0x504b,  0xa848,
+	0x0055,  0xf856,  0x7056,  0x8855,  0xe053,  0x1850,  0x9050,  0x6853,
+	0x405c,  0xb85f,  0x305f,  0xc85c,  0xa05a,  0x5859,  0xd059,  0x285a,
+	0x0066,  0xf865,  0x7065,  0x8866,  0xe060,  0x1863,  0x9063,  0x6860,
+	0x406f,  0xb86c,  0x306c,  0xc86f,  0xa069,  0x586a,  0xd06a,  0x2869,
+	0x8074,  0x7877,  0xf077,  0x0874,  0x6072,  0x9871,  0x1071,  0xe872,
+	0xc07d,  0x387e,  0xb07e,  0x487d,  0x207b,  0xd878,  0x5078,  0xa87b,
+	0x808b,  0x7888,  0xf088,  0x088b,  0x608d,  0x988e,  0x108e,  0xe88d,
+	0xc082,  0x3881,  0xb081,  0x4882,  0x2084,  0xd887,  0x5087,  0xa884,
+	0x0099,  0xf89a,  0x709a,  0x8899,  0xe09f,  0x189c,  0x909c,  0x689f,
+	0x4090,  0xb893,  0x3093,  0xc890,  0xa096,  0x5895,  0xd095,  0x2896,
+	0x00aa,  0xf8a9,  0x70a9,  0x88aa,  0xe0ac,  0x18af,  0x90af,  0x68ac,
+	0x40a3,  0xb8a0,  0x30a0,  0xc8a3,  0xa0a5,  0x58a6,  0xd0a6,  0x28a5,
+	0x80b8,  0x78bb,  0xf0bb,  0x08b8,  0x60be,  0x98bd,  0x10bd,  0xe8be,
+	0xc0b1,  0x38b2,  0xb0b2,  0x48b1,  0x20b7,  0xd8b4,  0x50b4,  0xa8b7,
+	0x00cc,  0xf8cf,  0x70cf,  0x88cc,  0xe0ca,  0x18c9,  0x90c9,  0x68ca,
+	0x40c5,  0xb8c6,  0x30c6,  0xc8c5,  0xa0c3,  0x58c0,  0xd0c0,  0x28c3,
+	0x80de,  0x78dd,  0xf0dd,  0x08de,  0x60d8,  0x98db,  0x10db,  0xe8d8,
+	0xc0d7,  0x38d4,  0xb0d4,  0x48d7,  0x20d1,  0xd8d2,  0x50d2,  0xa8d1,
+	0x80ed,  0x78ee,  0xf0ee,  0x08ed,  0x60eb,  0x98e8,  0x10e8,  0xe8eb,
+	0xc0e4,  0x38e7,  0xb0e7,  0x48e4,  0x20e2,  0xd8e1,  0x50e1,  0xa8e2,
+	0x00ff,  0xf8fc,  0x70fc,  0x88ff,  0xe0f9,  0x18fa,  0x90fa,  0x68f9,
+	0x40f6,  0xb8f5,  0x30f5,  0xc8f6,  0xa0f0,  0x58f3,  0xd0f3,  0x28f0 },
+
+  { 0x0000,  0x8113,  0x8223,  0x0330,  0x8443,  0x0550,  0x0660,  0x8773,
+	0x8883,  0x0990,  0x0aa0,  0x8bb3,  0x0cc0,  0x8dd3,  0x8ee3,  0x0ff0,
+	0x9103,  0x1010,  0x1320,  0x9233,  0x1540,  0x9453,  0x9763,  0x1670,
+	0x1980,  0x9893,  0x9ba3,  0x1ab0,  0x9dc3,  0x1cd0,  0x1fe0,  0x9ef3,
+	0xa203,  0x2310,  0x2020,  0xa133,  0x2640,  0xa753,  0xa463,  0x2570,
+	0x2a80,  0xab93,  0xa8a3,  0x29b0,  0xaec3,  0x2fd0,  0x2ce0,  0xadf3,
+	0x3300,  0xb213,  0xb123,  0x3030,  0xb743,  0x3650,  0x3560,  0xb473,
+	0xbb83,  0x3a90,  0x39a0,  0xb8b3,  0x3fc0,  0xbed3,  0xbde3,  0x3cf0,
+	0xc403,  0x4510,  0x4620,  0xc733,  0x4040,  0xc153,  0xc263,  0x4370,
+	0x4c80,  0xcd93,  0xcea3,  0x4fb0,  0xc8c3,  0x49d0,  0x4ae0,  0xcbf3,
+	0x5500,  0xd413,  0xd723,  0x5630,  0xd143,  0x5050,  0x5360,  0xd273,
+	0xdd83,  0x5c90,  0x5fa0,  0xdeb3,  0x59c0,  0xd8d3,  0xdbe3,  0x5af0,
+	0x6600,  0xe713,  0xe423,  0x6530,  0xe243,  0x6350,  0x6060,  0xe173,
+	0xee83,  0x6f90,  0x6ca0,  0xedb3,  0x6ac0,  0xebd3,  0xe8e3,  0x69f0,
+	0xf703,  0x7610,  0x7520,  0xf433,  0x7340,  0xf253,  0xf163,  0x7070,
+	0x7f80,  0xfe93,  0xfda3,  0x7cb0,  0xfbc3,  0x7ad0,  0x79e0,  0xf8f3,
+	0x0803,  0x8910,  0x8a20,  0x0b33,  0x8c40,  0x0d53,  0x0e63,  0x8f70,
+	0x8080,  0x0193,  0x02a3,  0x83b0,  0x04c3,  0x85d0,  0x86e0,  0x07f3,
+	0x9900,  0x1813,  0x1b23,  0x9a30,  0x1d43,  0x9c50,  0x9f60,  0x1e73,
+	0x1183,  0x9090,  0x93a0,  0x12b3,  0x95c0,  0x14d3,  0x17e3,  0x96f0,
+	0xaa00,  0x2b13,  0x2823,  0xa930,  0x2e43,  0xaf50,  0xac60,  0x2d73,
+	0x2283,  0xa390,  0xa0a0,  0x21b3,  0xa6c0,  0x27d3,  0x24e3,  0xa5f0,
+	0x3b03,  0xba10,  0xb920,  0x3833,  0xbf40,  0x3e53,  0x3d63,  0xbc70,
+	0xb380,  0x3293,  0x31a3,  0xb0b0,  0x37c3,  0xb6d0,  0xb5e0,  0x34f3,
+	0xcc00,  0x4d13,  0x4e23,  0xcf30,  0x4843,  0xc950,  0xca60,  0x4b73,
+	0x4483,  0xc590,  0xc6a0,  0x47b3,  0xc0c0,  0x41d3,  0x42e3,  0xc3f0,
+	0x5d03,  0xdc10,  0xdf20,  0x5e33,  0xd940,  0x5853,  0x5b63,  0xda70,
+	0xd580,  0x5493,  0x57a3,  0xd6b0,  0x51c3,  0xd0d0,  0xd3e0,  0x52f3,
+	0x6e03,  0xef10,  0xec20,  0x6d33,  0xea40,  0x6b53,  0x6863,  0xe970,
+	0xe680,  0x6793,  0x64a3,  0xe5b0,  0x62c3,  0xe3d0,  0xe0e0,  0x61f3,
+	0xff00,  0x7e13,  0x7d23,  0xfc30,  0x7b43,  0xfa50,  0xf960,  0x7873,
+	0x7783,  0xf690,  0xf5a0,  0x74b3,  0xf3c0,  0x72d3,  0x71e3,  0xf0f0 },
+
+  { 0x0000,  0x1006,  0x200c,  0x300a,  0x4018,  0x501e,  0x6014,  0x7012,
+	0x8030,  0x9036,  0xa03c,  0xb03a,  0xc028,  0xd02e,  0xe024,  0xf022,
+	0x8065,  0x9063,  0xa069,  0xb06f,  0xc07d,  0xd07b,  0xe071,  0xf077,
+	0x0055,  0x1053,  0x2059,  0x305f,  0x404d,  0x504b,  0x6041,  0x7047,
+	0x80cf,  0x90c9,  0xa0c3,  0xb0c5,  0xc0d7,  0xd0d1,  0xe0db,  0xf0dd,
+	0x00ff,  0x10f9,  0x20f3,  0x30f5,  0x40e7,  0x50e1,  0x60eb,  0x70ed,
+	0x00aa,  0x10ac,  0x20a6,  0x30a0,  0x40b2,  0x50b4,  0x60be,  0x70b8,
+	0x809a,  0x909c,  0xa096,  0xb090,  0xc082,  0xd084,  0xe08e,  0xf088,
+	0x819b,  0x919d,  0xa197,  0xb191,  0xc183,  0xd185,  0xe18f,  0xf189,
+	0x01ab,  0x11ad,  0x21a7,  0x31a1,  0x41b3,  0x51b5,  0x61bf,  0x71b9,
+	0x01fe,  0x11f8,  0x21f2,  0x31f4,  0x41e6,  0x51e0,  0x61ea,  0x71ec,
+	0x81ce,  0x91c8,  0xa1c2,  0xb1c4,  0xc1d6,  0xd1d0,  0xe1da,  0xf1dc,
+	0x0154,  0x1152,  0x2158,  0x315e,  0x414c,  0x514a,  0x6140,  0x7146,
+	0x8164,  0x9162,  0xa168,  0xb16e,  0xc17c,  0xd17a,  0xe170,  0xf176,
+	0x8131,  0x9137,  0xa13d,  0xb13b,  0xc129,  0xd12f,  0xe125,  0xf123,
+	0x0101,  0x1107,  0x210d,  0x310b,  0x4119,  0x511f,  0x6115,  0x7113,
+	0x8333,  0x9335,  0xa33f,  0xb339,  0xc32b,  0xd32d,  0xe327,  0xf321,
+	0x0303,  0x1305,  0x230f,  0x3309,  0x431b,  0x531d,  0x6317,  0x7311,
+	0x0356,  0x1350,  0x235a,  0x335c,  0x434e,  0x5348,  0x6342,  0x7344,
+	0x8366,  0x9360,  0xa36a,  0xb36c,  0xc37e,  0xd378,  0xe372,  0xf374,
+	0x03fc,  0x13fa,  0x23f0,  0x33f6,  0x43e4,  0x53e2,  0x63e8,  0x73ee,
+	0x83cc,  0x93ca,  0xa3c0,  0xb3c6,  0xc3d4,  0xd3d2,  0xe3d8,  0xf3de,
+	0x8399,  0x939f,  0xa395,  0xb393,  0xc381,  0xd387,  0xe38d,  0xf38b,
+	0x03a9,  0x13af,  0x23a5,  0x33a3,  0x43b1,  0x53b7,  0x63bd,  0x73bb,
+	0x02a8,  0x12ae,  0x22a4,  0x32a2,  0x42b0,  0x52b6,  0x62bc,  0x72ba,
+	0x8298,  0x929e,  0xa294,  0xb292,  0xc280,  0xd286,  0xe28c,  0xf28a,
+	0x82cd,  0x92cb,  0xa2c1,  0xb2c7,  0xc2d5,  0xd2d3,  0xe2d9,  0xf2df,
+	0x02fd,  0x12fb,  0x22f1,  0x32f7,  0x42e5,  0x52e3,  0x62e9,  0x72ef,
+	0x8267,  0x9261,  0xa26b,  0xb26d,  0xc27f,  0xd279,  0xe273,  0xf275,
+	0x0257,  0x1251,  0x225b,  0x325d,  0x424f,  0x5249,  0x6243,  0x7245,
+	0x0202,  0x1204,  0x220e,  0x3208,  0x421a,  0x521c,  0x6216,  0x7210,
+	0x8232,  0x9234,  0xa23e,  0xb238,  0xc22a,  0xd22c,  0xe226,  0xf220 }
+};
+
+#if 0
+void FLAC__crc16_init_table(void)
+{
+	int i, j;
+	FLAC__uint16 polynomial, crc;
+	polynomial = 0x8005;
+
+	for(i = 0; i <= 0xFF; i++){
+		crc = i << 8;
+
+		for(j = 0; j < 8; j++)
+			crc = (crc << 1) ^ (crc & (1 << 15) ? polynomial : 0);
+
+		FLAC__crc16_table[0][i] = crc;
+	}
+
+	for(i = 0; i <= 0xFF; i++)
+		for(j = 1; j < 8; j++)
+			FLAC__crc16_table[j][i] = FLAC__crc16_table[0][FLAC__crc16_table[j - 1][i] >> 8] ^ (FLAC__crc16_table[j - 1][i] << 8);
+}
+#endif
+
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len)
+{
+	FLAC__uint8 crc = 0;
+
+	while(len--)
+		crc = FLAC__crc8_table[crc ^ *data++];
+
+	return crc;
+}
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len)
+{
+	FLAC__uint16 crc = 0;
+
+	while(len >= 8){
+		crc ^= data[0] << 8 | data[1];
+
+		crc = FLAC__crc16_table[7][crc >> 8] ^ FLAC__crc16_table[6][crc & 0xFF] ^
+		      FLAC__crc16_table[5][data[2] ] ^ FLAC__crc16_table[4][data[3]   ] ^
+		      FLAC__crc16_table[3][data[4] ] ^ FLAC__crc16_table[2][data[5]   ] ^
+		      FLAC__crc16_table[1][data[6] ] ^ FLAC__crc16_table[0][data[7]   ];
+
+		data += 8;
+		len -= 8;
+	}
+
+	while(len--)
+		crc = (crc<<8) ^ FLAC__crc16_table[0][(crc>>8) ^ *data++];
+
+	return crc;
+}
+
+FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc)
+{
+	while (len >= 2) {
+		crc ^= words[0] >> 16;
+
+		crc = FLAC__crc16_table[7][crc >> 8               ] ^ FLAC__crc16_table[6][crc & 0xFF             ] ^
+		      FLAC__crc16_table[5][(words[0] >>  8) & 0xFF] ^ FLAC__crc16_table[4][ words[0]        & 0xFF] ^
+		      FLAC__crc16_table[3][ words[1] >> 24        ] ^ FLAC__crc16_table[2][(words[1] >> 16) & 0xFF] ^
+		      FLAC__crc16_table[1][(words[1] >>  8) & 0xFF] ^ FLAC__crc16_table[0][ words[1]        & 0xFF];
+
+		words += 2;
+		len -= 2;
+	}
+
+	if (len) {
+		crc ^= words[0] >> 16;
+
+		crc = FLAC__crc16_table[3][crc >> 8               ] ^ FLAC__crc16_table[2][crc & 0xFF             ] ^
+		      FLAC__crc16_table[1][(words[0] >>  8) & 0xFF] ^ FLAC__crc16_table[0][words[0]         & 0xFF];
+	}
+
+	return crc;
+}
+
+FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc)
+{
+	while (len--) {
+		crc ^= words[0] >> 48;
+
+		crc = FLAC__crc16_table[7][crc >> 8               ] ^ FLAC__crc16_table[6][crc & 0xFF             ] ^
+		      FLAC__crc16_table[5][(words[0] >> 40) & 0xFF] ^ FLAC__crc16_table[4][(words[0] >> 32) & 0xFF] ^
+		      FLAC__crc16_table[3][(words[0] >> 24) & 0xFF] ^ FLAC__crc16_table[2][(words[0] >> 16) & 0xFF] ^
+		      FLAC__crc16_table[1][(words[0] >>  8) & 0xFF] ^ FLAC__crc16_table[0][ words[0]        & 0xFF];
+
+		words++;
+	}
+
+	return crc;
+}
diff --git a/src/libFLAC/fixed.c b/src/libFLAC/fixed.c
new file mode 100644
index 0000000..5f48ba7
--- /dev/null
+++ b/src/libFLAC/fixed.c
@@ -0,0 +1,395 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 <string.h>
+#include "share/compat.h"
+#include "private/bitmath.h"
+#include "private/fixed.h"
+#include "private/macros.h"
+#include "FLAC/assert.h"
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x)))
+
+#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;
+	uint32_t 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 -= (int)(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, (uint32_t)(-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;
+	uint32_t 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 -= (int)(bits-16); // defined, but cast to int to avoid ubsan assert.
+	}
+	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, (uint32_t)(-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
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t 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]);
+	FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+	FLAC__int32 error, save;
+	FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+	uint32_t i, order;
+
+	for(i = 0; i < data_len; i++) {
+		error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
+		error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+		error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+		error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+		error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+	}
+
+	if(total_error_0 < 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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+		order = 1;
+	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;
+	else
+		order = 4;
+
+	/* Estimate the expected number of bits per residual signal sample. */
+	/* 'total_error*' is linearly related to the variance of the residual */
+	/* signal, so we use it directly to compute E(|x|) */
+	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (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;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t 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]);
+	FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+	FLAC__int32 error, save;
+	/* total_error_* are 64-bits to avoid overflow when encoding
+	 * erratic signals when the bits-per-sample and blocksize are
+	 * large.
+	 */
+	FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+	uint32_t i, order;
+
+	for(i = 0; i < data_len; i++) {
+		error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
+		error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+		error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+		error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+		error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+	}
+
+	if(total_error_0 < 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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+		order = 1;
+	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;
+	else
+		order = 4;
+
+	/* Estimate the expected number of bits per residual signal sample. */
+	/* 'total_error*' is linearly related to the variance of the residual */
+	/* signal, so we use it directly to compute E(|x|) */
+	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+#else
+	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;
+}
+
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[])
+{
+	const int idata_len = (int)data_len;
+	int i;
+
+	switch(order) {
+		case 0:
+			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++)
+				residual[i] = data[i] - data[i-1];
+			break;
+		case 2:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 2*data[i-1] + data[i-2];
+			break;
+		case 3:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+			break;
+		case 4:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+}
+
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[])
+{
+	int i, idata_len = (int)data_len;
+
+	switch(order) {
+		case 0:
+			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++)
+				data[i] = residual[i] + data[i-1];
+			break;
+		case 2:
+			for(i = 0; i < idata_len; i++)
+				data[i] = residual[i] + 2*data[i-1] - data[i-2];
+			break;
+		case 3:
+			for(i = 0; i < idata_len; i++)
+				data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
+			break;
+		case 4:
+			for(i = 0; i < idata_len; i++)
+				data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+}
diff --git a/src/libFLAC/fixed_intrin_sse2.c b/src/libFLAC/fixed_intrin_sse2.c
new file mode 100644
index 0000000..47258e9
--- /dev/null
+++ b/src/libFLAC/fixed_intrin_sse2.c
@@ -0,0 +1,255 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+#include "private/fixed.h"
+#ifdef FLAC__SSE2_SUPPORTED
+
+#include <emmintrin.h> /* SSE2 */
+#include <math.h>
+#include "private/macros.h"
+#include "share/compat.h"
+#include "FLAC/assert.h"
+
+#ifdef FLAC__CPU_IA32
+#define m128i_to_i64(dest, src) _mm_storel_epi64((__m128i*)&dest, src)
+#else
+#define m128i_to_i64(dest, src) dest = _mm_cvtsi128_si64(src)
+#endif
+
+FLAC__SSE_TARGET("sse2")
+uint32_t FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+	FLAC__uint32 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
+	uint32_t i, order;
+
+	__m128i total_err0, total_err1, total_err2;
+
+	{
+		FLAC__int32 itmp;
+		__m128i last_error;
+
+		last_error = _mm_cvtsi32_si128(data[-1]);							// 0   0   0   le0
+		itmp = data[-2];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   0   le0 le1
+		itmp -= data[-3];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   le0 le1 le2
+		itmp -= data[-3] - data[-4];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// le0 le1 le2 le3
+
+		total_err0 = total_err1 = _mm_setzero_si128();
+		for(i = 0; i < data_len; i++) {
+			__m128i err0, err1, tmp;
+			err0 = _mm_cvtsi32_si128(data[i]);								// 0   0   0   e0
+			err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(0,0,0,0));			// e0  e0  e0  e0
+#if 1 /* OPT_SSE */
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   le0 le1 le2
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   0   le0 le1
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   0   0   le0
+			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
+#else
+			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 8));	// le0  le1  le2+le0  le3+le1
+			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 4));	// le0  le1+le0  le2+le0+le1  le3+le1+le2+le0
+			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
+#endif
+			tmp = _mm_slli_si128(err0, 12);									// e0   0   0   0
+			last_error = _mm_srli_si128(err1, 4);							//  0  e1  e2  e3
+			last_error = _mm_or_si128(last_error, tmp);						// e0  e1  e2  e3
+
+			tmp = _mm_srai_epi32(err0, 31);
+			err0 = _mm_xor_si128(err0, tmp);
+			err0 = _mm_sub_epi32(err0, tmp);
+			tmp = _mm_srai_epi32(err1, 31);
+			err1 = _mm_xor_si128(err1, tmp);
+			err1 = _mm_sub_epi32(err1, tmp);
+
+			total_err0 = _mm_add_epi32(total_err0, err0);					// 0   0   0   te0
+			total_err1 = _mm_add_epi32(total_err1, err1);					// te1 te2 te3 te4
+		}
+	}
+
+	total_error_0 = _mm_cvtsi128_si32(total_err0);
+	total_err2 = total_err1;											// te1  te2  te3  te4
+	total_err1 = _mm_srli_si128(total_err1, 8);							//  0    0   te1  te2
+	total_error_4 = _mm_cvtsi128_si32(total_err2);
+	total_error_2 = _mm_cvtsi128_si32(total_err1);
+	total_err2 = _mm_srli_si128(total_err2,	4);							//  0   te1  te2  te3
+	total_err1 = _mm_srli_si128(total_err1, 4);							//  0    0    0   te1
+	total_error_3 = _mm_cvtsi128_si32(total_err2);
+	total_error_1 = _mm_cvtsi128_si32(total_err1);
+
+	/* prefer higher order */
+	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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+		order = 1;
+	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;
+	else
+		order = 4;
+
+	/* Estimate the expected number of bits per residual signal sample. */
+	/* 'total_error*' is linearly related to the variance of the residual */
+	/* signal, so we use it directly to compute E(|x|) */
+	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+
+	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+
+	return order;
+}
+
+FLAC__SSE_TARGET("sse2")
+uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+	FLAC__uint64 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
+	uint32_t i, order;
+
+	__m128i total_err0, total_err1, total_err3;
+
+	{
+		FLAC__int32 itmp;
+		__m128i last_error, zero = _mm_setzero_si128();
+
+		last_error = _mm_cvtsi32_si128(data[-1]);							// 0   0   0   le0
+		itmp = data[-2];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   0   le0 le1
+		itmp -= data[-3];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   le0 le1 le2
+		itmp -= data[-3] - data[-4];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// le0 le1 le2 le3
+
+		total_err0 = total_err1 = total_err3 = _mm_setzero_si128();
+		for(i = 0; i < data_len; i++) {
+			__m128i err0, err1, tmp;
+			err0 = _mm_cvtsi32_si128(data[i]);								// 0   0   0   e0
+			err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(0,0,0,0));			// e0  e0  e0  e0
+#if 1 /* OPT_SSE */
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   le0 le1 le2
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   0   le0 le1
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   0   0   le0
+			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
+#else
+			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 8));	// le0  le1  le2+le0  le3+le1
+			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 4));	// le0  le1+le0  le2+le0+le1  le3+le1+le2+le0
+			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
+#endif
+			tmp = _mm_slli_si128(err0, 12);									// e0   0   0   0
+			last_error = _mm_srli_si128(err1, 4);							//  0  e1  e2  e3
+			last_error = _mm_or_si128(last_error, tmp);						// e0  e1  e2  e3
+
+			tmp = _mm_srai_epi32(err0, 31);
+			err0 = _mm_xor_si128(err0, tmp);
+			err0 = _mm_sub_epi32(err0, tmp);
+			tmp = _mm_srai_epi32(err1, 31);
+			err1 = _mm_xor_si128(err1, tmp);
+			err1 = _mm_sub_epi32(err1, tmp);
+
+			total_err0 = _mm_add_epi64(total_err0, err0);					//        0       te0
+			err0 = _mm_unpacklo_epi32(err1, zero);							//   0  |e3|   0  |e4|
+			err1 = _mm_unpackhi_epi32(err1, zero);							//   0  |e1|   0  |e2|
+			total_err3 = _mm_add_epi64(total_err3, err0);					//       te3      te4
+			total_err1 = _mm_add_epi64(total_err1, err1);					//       te1      te2
+		}
+	}
+
+	m128i_to_i64(total_error_0, total_err0);
+	m128i_to_i64(total_error_4, total_err3);
+	m128i_to_i64(total_error_2, total_err1);
+	total_err3 = _mm_srli_si128(total_err3,	8);							//         0      te3
+	total_err1 = _mm_srli_si128(total_err1, 8);							//         0      te1
+	m128i_to_i64(total_error_3, total_err3);
+	m128i_to_i64(total_error_1, total_err1);
+
+	/* prefer higher order */
+	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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+		order = 1;
+	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;
+	else
+		order = 4;
+
+	/* Estimate the expected number of bits per residual signal sample. */
+	/* 'total_error*' is linearly related to the variance of the residual */
+	/* signal, so we use it directly to compute E(|x|) */
+	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+
+	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+
+	return order;
+}
+
+#endif /* FLAC__SSE2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/fixed_intrin_ssse3.c b/src/libFLAC/fixed_intrin_ssse3.c
new file mode 100644
index 0000000..2a61e83
--- /dev/null
+++ b/src/libFLAC/fixed_intrin_ssse3.c
@@ -0,0 +1,243 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/fixed.h"
+#ifdef FLAC__SSSE3_SUPPORTED
+
+#include <tmmintrin.h> /* SSSE3 */
+#include <math.h>
+#include "private/macros.h"
+#include "share/compat.h"
+#include "FLAC/assert.h"
+
+#ifdef FLAC__CPU_IA32
+#define m128i_to_i64(dest, src) _mm_storel_epi64((__m128i*)&dest, src)
+#else
+#define m128i_to_i64(dest, src) dest = _mm_cvtsi128_si64(src)
+#endif
+
+FLAC__SSE_TARGET("ssse3")
+uint32_t FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+	FLAC__uint32 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
+	uint32_t i, order;
+
+	__m128i total_err0, total_err1, total_err2;
+
+	{
+		FLAC__int32 itmp;
+		__m128i last_error;
+
+		last_error = _mm_cvtsi32_si128(data[-1]);							// 0   0   0   le0
+		itmp = data[-2];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   0   le0 le1
+		itmp -= data[-3];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   le0 le1 le2
+		itmp -= data[-3] - data[-4];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// le0 le1 le2 le3
+
+		total_err0 = total_err1 = _mm_setzero_si128();
+		for(i = 0; i < data_len; i++) {
+			__m128i err0, err1;
+			err0 = _mm_cvtsi32_si128(data[i]);								// 0   0   0   e0
+			err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(0,0,0,0));			// e0  e0  e0  e0
+#if 1 /* OPT_SSE */
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   le0 le1 le2
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   0   le0 le1
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   0   0   le0
+			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
+#else
+			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 8));	// le0  le1  le2+le0  le3+le1
+			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 4));	// le0  le1+le0  le2+le0+le1  le3+le1+le2+le0
+			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
+#endif
+			last_error = _mm_alignr_epi8(err0, err1, 4);					// e0  e1  e2  e3
+
+			err0 = _mm_abs_epi32(err0);
+			err1 = _mm_abs_epi32(err1);
+
+			total_err0 = _mm_add_epi32(total_err0, err0);					// 0   0   0   te0
+			total_err1 = _mm_add_epi32(total_err1, err1);					// te1 te2 te3 te4
+		}
+	}
+
+	total_error_0 = _mm_cvtsi128_si32(total_err0);
+	total_err2 = total_err1;											// te1  te2  te3  te4
+	total_err1 = _mm_srli_si128(total_err1, 8);							//  0    0   te1  te2
+	total_error_4 = _mm_cvtsi128_si32(total_err2);
+	total_error_2 = _mm_cvtsi128_si32(total_err1);
+	total_err2 = _mm_srli_si128(total_err2,	4);							//  0   te1  te2  te3
+	total_err1 = _mm_srli_si128(total_err1, 4);							//  0    0    0   te1
+	total_error_3 = _mm_cvtsi128_si32(total_err2);
+	total_error_1 = _mm_cvtsi128_si32(total_err1);
+
+	/* prefer higher order */
+	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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+		order = 1;
+	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;
+	else
+		order = 4;
+
+	/* Estimate the expected number of bits per residual signal sample. */
+	/* 'total_error*' is linearly related to the variance of the residual */
+	/* signal, so we use it directly to compute E(|x|) */
+	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+
+	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+
+	return order;
+}
+
+FLAC__SSE_TARGET("ssse3")
+uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+	FLAC__uint64 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
+	uint32_t i, order;
+
+	__m128i total_err0, total_err1, total_err3;
+
+	{
+		FLAC__int32 itmp;
+		__m128i last_error, zero = _mm_setzero_si128();
+
+		last_error = _mm_cvtsi32_si128(data[-1]);							// 0   0   0   le0
+		itmp = data[-2];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   0   le0 le1
+		itmp -= data[-3];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// 0   le0 le1 le2
+		itmp -= data[-3] - data[-4];
+		last_error = _mm_shuffle_epi32(last_error, _MM_SHUFFLE(2,1,0,0));
+		last_error = _mm_sub_epi32(last_error, _mm_cvtsi32_si128(itmp));	// le0 le1 le2 le3
+
+		total_err0 = total_err1 = total_err3 = _mm_setzero_si128();
+		for(i = 0; i < data_len; i++) {
+			__m128i err0, err1;
+			err0 = _mm_cvtsi32_si128(data[i]);								// 0   0   0   e0
+			err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(0,0,0,0));			// e0  e0  e0  e0
+#if 1 /* OPT_SSE */
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   le0 le1 le2
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   0   le0 le1
+			err1 = _mm_sub_epi32(err1, last_error);
+			last_error = _mm_srli_si128(last_error, 4);						// 0   0   0   le0
+			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
+#else
+			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 8));	// le0  le1  le2+le0  le3+le1
+			last_error = _mm_add_epi32(last_error, _mm_srli_si128(last_error, 4));	// le0  le1+le0  le2+le0+le1  le3+le1+le2+le0
+			err1 = _mm_sub_epi32(err1, last_error);							// e1  e2  e3  e4
+#endif
+			last_error = _mm_alignr_epi8(err0, err1, 4);					// e0  e1  e2  e3
+
+			err0 = _mm_abs_epi32(err0);
+			err1 = _mm_abs_epi32(err1);										// |e1| |e2| |e3| |e4|
+
+			total_err0 = _mm_add_epi64(total_err0, err0);					//        0       te0
+			err0 = _mm_unpacklo_epi32(err1, zero);							//   0  |e3|   0  |e4|
+			err1 = _mm_unpackhi_epi32(err1, zero);							//   0  |e1|   0  |e2|
+			total_err3 = _mm_add_epi64(total_err3, err0);					//       te3      te4
+			total_err1 = _mm_add_epi64(total_err1, err1);					//       te1      te2
+		}
+	}
+
+	m128i_to_i64(total_error_0, total_err0);
+	m128i_to_i64(total_error_4, total_err3);
+	m128i_to_i64(total_error_2, total_err1);
+	total_err3 = _mm_srli_si128(total_err3,	8);							//         0      te3
+	total_err1 = _mm_srli_si128(total_err1, 8);							//         0      te1
+	m128i_to_i64(total_error_3, total_err3);
+	m128i_to_i64(total_error_1, total_err1);
+
+	/* prefer higher order */
+	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 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+		order = 1;
+	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;
+	else
+		order = 4;
+
+	/* Estimate the expected number of bits per residual signal sample. */
+	/* 'total_error*' is linearly related to the variance of the residual */
+	/* signal, so we use it directly to compute E(|x|) */
+	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+
+	residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+
+	return order;
+}
+
+#endif /* FLAC__SSSE3_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/flac.pc.in b/src/libFLAC/flac.pc.in
new file mode 100644
index 0000000..56e8594
--- /dev/null
+++ b/src/libFLAC/flac.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: FLAC
+Description: Free Lossless Audio Codec Library
+Version: @VERSION@
+Requires.private: @OGG_PACKAGE@
+Libs: -L${libdir} -lFLAC
+Libs.private: -lm
+Cflags: -I${includedir}
diff --git a/src/libFLAC/float.c b/src/libFLAC/float.c
new file mode 100644
index 0000000..a49a083
--- /dev/null
+++ b/src/libFLAC/float.c
@@ -0,0 +1,302 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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, uint32_t fracbits, uint32_t 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 */
diff --git a/src/libFLAC/format.c b/src/libFLAC/format.c
new file mode 100644
index 0000000..a62219f
--- /dev/null
+++ b/src/libFLAC/format.c
@@ -0,0 +1,589 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 <stdio.h>
+#include <stdlib.h> /* for qsort() */
+#include <string.h> /* for memset() */
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "private/format.h"
+#include "private/macros.h"
+
+/* PACKAGE_VERSION should come from configure */
+FLAC_API const char *FLAC__VERSION_STRING = PACKAGE_VERSION;
+
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " PACKAGE_VERSION " 20190804";
+
+FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
+FLAC_API const uint32_t FLAC__STREAM_SYNC = 0x664C6143;
+FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
+
+FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
+
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC = 0x3ffe;
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
+
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
+
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+FLAC_API const uint32_t 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_RICE2"
+};
+
+FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
+
+FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
+
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
+
+FLAC_API const char * const FLAC__SubframeTypeString[] = {
+	"CONSTANT",
+	"VERBATIM",
+	"FIXED",
+	"LPC"
+};
+
+FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
+	"INDEPENDENT",
+	"LEFT_SIDE",
+	"RIGHT_SIDE",
+	"MID_SIDE"
+};
+
+FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
+	"FRAME_NUMBER_TYPE_FRAME_NUMBER",
+	"FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
+};
+
+FLAC_API const char * const FLAC__MetadataTypeString[] = {
+	"STREAMINFO",
+	"PADDING",
+	"APPLICATION",
+	"SEEKTABLE",
+	"VORBIS_COMMENT",
+	"CUESHEET",
+	"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(uint32_t 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(uint32_t blocksize, uint32_t 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(uint32_t sample_rate)
+{
+	if(
+		!FLAC__format_sample_rate_is_valid(sample_rate) ||
+		(
+			sample_rate >= (1u << 16) &&
+			!(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
+		)
+	) {
+		return false;
+	}
+	else
+		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)
+{
+	uint32_t i;
+	FLAC__uint64 prev_sample_number = 0;
+	FLAC__bool got_prev = false;
+
+	FLAC__ASSERT(0 != seek_table);
+
+	for(i = 0; i < seek_table->num_points; i++) {
+		if(got_prev) {
+			if(
+				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+				seek_table->points[i].sample_number <= prev_sample_number
+			)
+				return false;
+		}
+		prev_sample_number = seek_table->points[i].sample_number;
+		got_prev = true;
+	}
+
+	return true;
+}
+
+/* used as the sort predicate for qsort() */
+static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
+{
+	/* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
+	if(l->sample_number == r->sample_number)
+		return 0;
+	else if(l->sample_number < r->sample_number)
+		return -1;
+	else
+		return 1;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
+{
+	uint32_t i, j;
+	FLAC__bool first;
+
+	FLAC__ASSERT(0 != seek_table);
+
+	if (seek_table->num_points == 0)
+		return 0;
+
+	/* sort the seekpoints */
+	qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
+
+	/* uniquify the seekpoints */
+	first = true;
+	for(i = j = 0; i < seek_table->num_points; i++) {
+		if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
+			if(!first) {
+				if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
+					continue;
+			}
+		}
+		first = false;
+		seek_table->points[j++] = seek_table->points[i];
+	}
+
+	for(i = j; i < seek_table->num_points; i++) {
+		seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+		seek_table->points[i].stream_offset = 0;
+		seek_table->points[i].frame_samples = 0;
+	}
+
+	return j;
+}
+
+/*
+ * 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 uint32_t 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, uint32_t length)
+{
+	if(length == (uint32_t)(-1)) {
+		while(*value) {
+			uint32_t n = utf8len_(value);
+			if(n == 0)
+				return false;
+			value += n;
+		}
+	}
+	else {
+		const FLAC__byte *end = value + length;
+		while(value < end) {
+			uint32_t 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, uint32_t 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) {
+		uint32_t 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)
+{
+	uint32_t i, j;
+
+	if(check_cd_da_subset) {
+		if(cue_sheet->lead_in < 2 * 44100) {
+			if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
+			return false;
+		}
+		if(cue_sheet->lead_in % 588 != 0) {
+			if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
+			return false;
+		}
+	}
+
+	if(cue_sheet->num_tracks == 0) {
+		if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
+		return false;
+	}
+
+	if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
+		if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
+		return false;
+	}
+
+	for(i = 0; i < cue_sheet->num_tracks; i++) {
+		if(cue_sheet->tracks[i].number == 0) {
+			if(violation) *violation = "cue sheet may not have a track number 0";
+			return false;
+		}
+
+		if(check_cd_da_subset) {
+			if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
+				if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
+				return false;
+			}
+		}
+
+		if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
+			if(violation) {
+				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;
+		}
+
+		if(i < cue_sheet->num_tracks - 1) {
+			if(cue_sheet->tracks[i].num_indices == 0) {
+				if(violation) *violation = "cue sheet track must have at least one index point";
+				return false;
+			}
+
+			if(cue_sheet->tracks[i].indices[0].number > 1) {
+				if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
+				return false;
+			}
+		}
+
+		for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
+			if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
+				if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
+				return false;
+			}
+
+			if(j > 0) {
+				if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
+					if(violation) *violation = "cue sheet track index numbers must increase by 1";
+					return false;
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+/* @@@@ 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; ) {
+		uint32_t 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
+ */
+uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order)
+{
+	return
+		FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
+			FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
+			blocksize,
+			predictor_order
+		);
+}
+
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize)
+{
+	uint32_t max_rice_partition_order = 0;
+	while(!(blocksize & 1)) {
+		max_rice_partition_order++;
+		blocksize >>= 1;
+	}
+	return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
+}
+
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order)
+{
+	uint32_t max_rice_partition_order = limit;
+
+	while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
+		max_rice_partition_order--;
+
+	FLAC__ASSERT(
+		(max_rice_partition_order == 0 && blocksize >= predictor_order) ||
+		(max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
+	);
+
+	return max_rice_partition_order;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+	FLAC__ASSERT(0 != object);
+
+	object->parameters = 0;
+	object->raw_bits = 0;
+	object->capacity_by_order = 0;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+	FLAC__ASSERT(0 != object);
+
+	if(0 != object->parameters)
+		free(object->parameters);
+	if(0 != object->raw_bits)
+		free(object->raw_bits);
+	FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
+}
+
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order)
+{
+	FLAC__ASSERT(0 != object);
+
+	FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
+
+	if(object->capacity_by_order < max_partition_order) {
+		if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(uint32_t)*(1 << max_partition_order))))
+			return false;
+		if(0 == (object->raw_bits = safe_realloc_(object->raw_bits, sizeof(uint32_t)*(1 << max_partition_order))))
+			return false;
+		memset(object->raw_bits, 0, sizeof(uint32_t)*(1 << max_partition_order));
+		object->capacity_by_order = max_partition_order;
+	}
+
+	return true;
+}
diff --git a/src/libFLAC/ia32/CMakeLists.txt b/src/libFLAC/ia32/CMakeLists.txt
new file mode 100644
index 0000000..96b1c74
--- /dev/null
+++ b/src/libFLAC/ia32/CMakeLists.txt
@@ -0,0 +1,17 @@
+#include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
+add_compile_options(-I${CMAKE_CURRENT_SOURCE_DIR}/)
+
+if(APPLE)
+    add_compile_options(-dOBJ_FORMAT_macho)
+elseif(WIN32)
+    #add_compile_options(-d OBJ_FORMAT_win32)
+    # FIXME the command above doesn't seem to work on Windows
+    set(CMAKE_ASM_NASM_FLAGS -dOBJ_FORMAT_win32)
+else()
+    add_compile_options(-dOBJ_FORMAT_elf)
+endif()
+
+add_library(FLAC-asm OBJECT
+    cpu_asm.nasm
+    fixed_asm.nasm
+    lpc_asm.nasm)
diff --git a/src/libFLAC/ia32/Makefile.am b/src/libFLAC/ia32/Makefile.am
new file mode 100644
index 0000000..fd3d95a
--- /dev/null
+++ b/src/libFLAC/ia32/Makefile.am
@@ -0,0 +1,46 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+SUFFIXES = .nasm .lo
+
+STRIP_NON_ASM = sh $(top_srcdir)/strip_non_asm_libtool_args.sh
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+.nasm.lo:
+	$(LIBTOOL) --tag=CC --mode=compile $(STRIP_NON_ASM) $(NASM) -f $(OBJ_FORMAT) -d OBJ_FORMAT_$(OBJ_FORMAT) -i$(srcdir)/ $< -o $@
+
+noinst_LTLIBRARIES = libFLAC-asm.la
+libFLAC_asm_la_SOURCES = \
+	cpu_asm.nasm \
+	fixed_asm.nasm \
+	lpc_asm.nasm \
+	nasm.h
+
+EXTRA_DIST = CMakeLists.txt
diff --git a/src/libFLAC/ia32/cpu_asm.nasm b/src/libFLAC/ia32/cpu_asm.nasm
new file mode 100644
index 0000000..dc031d5
--- /dev/null
+++ b/src/libFLAC/ia32/cpu_asm.nasm
@@ -0,0 +1,119 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001-2009  Josh Coalson
+;  Copyright (C) 2011-2016  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 "nasm.h"
+
+	data_section
+
+cglobal FLAC__cpu_have_cpuid_asm_ia32
+cglobal FLAC__cpu_info_asm_ia32
+
+	code_section
+
+; **********************************************************************
+;
+; FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32()
+;
+
+cident FLAC__cpu_have_cpuid_asm_ia32
+	pushfd
+	pop	eax
+	mov	edx, eax
+	xor	eax, 0x00200000
+	push	eax
+	popfd
+	pushfd
+	pop	eax
+	xor	eax, edx
+	and	eax, 0x00200000
+	shr	eax, 0x15
+	push	edx
+	popfd
+	ret
+
+
+; **********************************************************************
+;
+; void FLAC__cpu_info_asm_ia32(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
+;
+
+cident FLAC__cpu_info_asm_ia32
+	;[esp + 8] == level
+	;[esp + 12] == flags_eax
+	;[esp + 16] == flags_ebx
+	;[esp + 20] == flags_ecx
+	;[esp + 24] == flags_edx
+
+	push	ebx
+	call	FLAC__cpu_have_cpuid_asm_ia32
+	test	eax, eax
+	jz	.no_cpuid
+
+	mov	eax, [esp + 8]
+	and	eax, 0x80000000
+	cpuid
+	cmp	eax, [esp + 8]
+	jb	.no_cpuid
+	xor	ecx, ecx
+	mov	eax, [esp + 8]
+	cpuid
+
+	push	ebx
+	;[esp + 16] == flags_eax
+	mov	ebx, [esp + 16]
+	mov	[ebx], eax
+	pop	eax
+	;[esp + 16] == flags_ebx
+	mov	ebx, [esp + 16]
+	mov	[ebx], eax
+	mov	ebx, [esp + 20]
+	mov	[ebx], ecx
+	mov	ebx, [esp + 24]
+	mov	[ebx], edx
+	jmp	.end
+
+.no_cpuid:
+	xor	eax, eax
+	mov	ebx, [esp + 12]
+	mov	[ebx], eax
+	mov	ebx, [esp + 16]
+	mov	[ebx], eax
+	mov	ebx, [esp + 20]
+	mov	[ebx], eax
+	mov	ebx, [esp + 24]
+	mov	[ebx], eax
+.end:
+	pop	ebx
+	ret
+
+; end
diff --git a/src/libFLAC/ia32/fixed_asm.nasm b/src/libFLAC/ia32/fixed_asm.nasm
new file mode 100644
index 0000000..8477724
--- /dev/null
+++ b/src/libFLAC/ia32/fixed_asm.nasm
@@ -0,0 +1,309 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001-2009  Josh Coalson
+;  Copyright (C) 2011-2016  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 "nasm.h"
+
+	data_section
+
+cglobal FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov
+
+	code_section
+
+; **********************************************************************
+;
+; unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 *data, unsigned data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+; {
+; 	FLAC__int32 last_error_0 = data[-1];
+; 	FLAC__int32 last_error_1 = data[-1] - data[-2];
+; 	FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+; 	FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+; 	FLAC__int32 error, save;
+; 	FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+; 	unsigned i, order;
+;
+; 	for(i = 0; i < data_len; i++) {
+; 		error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
+; 		error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+; 		error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+; 		error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+; 		error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+; 	}
+;
+; 	if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+; 		order = 0;
+; 	else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+; 		order = 1;
+; 	else if(total_error_2 < min(total_error_3, total_error_4))
+; 		order = 2;
+; 	else if(total_error_3 < total_error_4)
+; 		order = 3;
+; 	else
+; 		order = 4;
+;
+; 	residual_bits_per_sample[0] = (float)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+; 	residual_bits_per_sample[1] = (float)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+; 	residual_bits_per_sample[2] = (float)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+; 	residual_bits_per_sample[3] = (float)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+; 	residual_bits_per_sample[4] = (float)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+;
+; 	return order;
+; }
+	ALIGN 16
+cident FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov
+
+	; esp + 36 == data[]
+	; esp + 40 == data_len
+	; esp + 44 == residual_bits_per_sample[]
+
+	push	ebp
+	push	ebx
+	push	esi
+	push	edi
+	sub	esp, byte 16
+	; qword [esp] == temp space for loading FLAC__uint64s to FPU regs
+
+	; ebx == &data[i]
+	; ecx == loop counter (i)
+	; ebp == order
+	; mm0 == total_error_1:total_error_0
+	; mm1 == total_error_2:total_error_3
+	; mm2 == :total_error_4
+	; mm3 == last_error_1:last_error_0
+	; mm4 == last_error_2:last_error_3
+
+	mov	ecx, [esp + 40]			; ecx = data_len
+	test	ecx, ecx
+	jz	near .data_len_is_0
+
+	mov	ebx, [esp + 36]			; ebx = data[]
+	movd	mm3, [ebx - 4]			; mm3 = 0:last_error_0
+	movd	mm2, [ebx - 8]			; mm2 = 0:data[-2]
+	movd	mm1, [ebx - 12]			; mm1 = 0:data[-3]
+	movd	mm0, [ebx - 16]			; mm0 = 0:data[-4]
+	movq	mm5, mm3			; mm5 = 0:last_error_0
+	psubd	mm5, mm2			; mm5 = 0:last_error_1
+	punpckldq	mm3, mm5		; mm3 = last_error_1:last_error_0
+	psubd	mm2, mm1			; mm2 = 0:data[-2] - data[-3]
+	psubd	mm5, mm2			; mm5 = 0:last_error_2
+	movq	mm4, mm5			; mm4 = 0:last_error_2
+	psubd	mm4, mm2			; mm4 = 0:last_error_2 - (data[-2] - data[-3])
+	paddd	mm4, mm1			; mm4 = 0:last_error_2 - (data[-2] - 2 * data[-3])
+	psubd	mm4, mm0			; mm4 = 0:last_error_3
+	punpckldq	mm4, mm5		; mm4 = last_error_2:last_error_3
+	pxor	mm0, mm0			; mm0 = total_error_1:total_error_0
+	pxor	mm1, mm1			; mm1 = total_error_2:total_error_3
+	pxor	mm2, mm2			; mm2 = 0:total_error_4
+
+	ALIGN 16
+.loop:
+	movd	mm7, [ebx]			; mm7 = 0:error_0
+	add	ebx, byte 4
+	movq	mm6, mm7			; mm6 = 0:error_0
+	psubd	mm7, mm3			; mm7 = :error_1
+	punpckldq	mm6, mm7		; mm6 = error_1:error_0
+	movq	mm5, mm6			; mm5 = error_1:error_0
+	movq	mm7, mm6			; mm7 = error_1:error_0
+	psubd	mm5, mm3			; mm5 = error_2:
+	movq	mm3, mm6			; mm3 = error_1:error_0
+	psrad	mm6, 31
+	pxor	mm7, mm6
+	psubd	mm7, mm6			; mm7 = abs(error_1):abs(error_0)
+	paddd	mm0, mm7			; mm0 = total_error_1:total_error_0
+	movq	mm6, mm5			; mm6 = error_2:
+	psubd	mm5, mm4			; mm5 = error_3:
+	punpckhdq	mm5, mm6		; mm5 = error_2:error_3
+	movq	mm7, mm5			; mm7 = error_2:error_3
+	movq	mm6, mm5			; mm6 = error_2:error_3
+	psubd	mm5, mm4			; mm5 = :error_4
+	movq	mm4, mm6			; mm4 = error_2:error_3
+	psrad	mm6, 31
+	pxor	mm7, mm6
+	psubd	mm7, mm6			; mm7 = abs(error_2):abs(error_3)
+	paddd	mm1, mm7			; mm1 = total_error_2:total_error_3
+	movq	mm6, mm5			; mm6 = :error_4
+	psrad	mm5, 31
+	pxor	mm6, mm5
+	psubd	mm6, mm5			; mm6 = :abs(error_4)
+	paddd	mm2, mm6			; mm2 = :total_error_4
+
+	dec	ecx
+	jnz	short .loop
+
+; 	if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+; 		order = 0;
+; 	else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+; 		order = 1;
+; 	else if(total_error_2 < min(total_error_3, total_error_4))
+; 		order = 2;
+; 	else if(total_error_3 < total_error_4)
+; 		order = 3;
+; 	else
+; 		order = 4;
+	movq	mm3, mm0			; mm3 = total_error_1:total_error_0
+	movd	edi, mm2			; edi = total_error_4
+	movd	esi, mm1			; esi = total_error_3
+	movd	eax, mm0			; eax = total_error_0
+	punpckhdq	mm1, mm1		; mm1 = total_error_2:total_error_2
+	punpckhdq	mm3, mm3		; mm3 = total_error_1:total_error_1
+	movd	edx, mm1			; edx = total_error_2
+	movd	ecx, mm3			; ecx = total_error_1
+
+	xor	ebx, ebx
+	xor	ebp, ebp
+	inc	ebx
+	cmp	ecx, eax
+	cmovb	eax, ecx			; eax = min(total_error_0, total_error_1)
+	cmovbe	ebp, ebx
+	inc	ebx
+	cmp	edx, eax
+	cmovb	eax, edx			; eax = min(total_error_0, total_error_1, total_error_2)
+	cmovbe	ebp, ebx
+	inc	ebx
+	cmp	esi, eax
+	cmovb	eax, esi			; eax = min(total_error_0, total_error_1, total_error_2, total_error_3)
+	cmovbe	ebp, ebx
+	inc	ebx
+	cmp	edi, eax
+	cmovb	eax, edi			; eax = min(total_error_0, total_error_1, total_error_2, total_error_3, total_error_4)
+	cmovbe	ebp, ebx
+	movd	ebx, mm0			; ebx = total_error_0
+	emms
+
+	; 	residual_bits_per_sample[0] = (float)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	; 	residual_bits_per_sample[1] = (float)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	; 	residual_bits_per_sample[2] = (float)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	; 	residual_bits_per_sample[3] = (float)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	; 	residual_bits_per_sample[4] = (float)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+	xor	eax, eax
+	fild	dword [esp + 40]		; ST = data_len (NOTE: assumes data_len is <2gigs)
+.rbps_0:
+	test	ebx, ebx
+	jz	.total_error_0_is_0
+	fld1					; ST = 1.0 data_len
+	mov	[esp], ebx
+	mov	[esp + 4], eax			; [esp] = (FLAC__uint64)total_error_0
+	mov	ebx, [esp + 44]
+	fild	qword [esp]			; ST = total_error_0 1.0 data_len
+	fdiv	st2				; ST = total_error_0/data_len 1.0 data_len
+	fldln2					; ST = ln2 total_error_0/data_len 1.0 data_len
+	fmulp	st1				; ST = ln2*total_error_0/data_len 1.0 data_len
+	fyl2x					; ST = log2(ln2*total_error_0/data_len) data_len
+	fstp	dword [ebx]			; residual_bits_per_sample[0] = log2(ln2*total_error_0/data_len)   ST = data_len
+	jmp	short .rbps_1
+.total_error_0_is_0:
+	mov	ebx, [esp + 44]
+	mov	[ebx], eax			; residual_bits_per_sample[0] = 0.0
+.rbps_1:
+	test	ecx, ecx
+	jz	.total_error_1_is_0
+	fld1					; ST = 1.0 data_len
+	mov	[esp], ecx
+	mov	[esp + 4], eax			; [esp] = (FLAC__uint64)total_error_1
+	fild	qword [esp]			; ST = total_error_1 1.0 data_len
+	fdiv	st2				; ST = total_error_1/data_len 1.0 data_len
+	fldln2					; ST = ln2 total_error_1/data_len 1.0 data_len
+	fmulp	st1				; ST = ln2*total_error_1/data_len 1.0 data_len
+	fyl2x					; ST = log2(ln2*total_error_1/data_len) data_len
+	fstp	dword [ebx + 4]			; residual_bits_per_sample[1] = log2(ln2*total_error_1/data_len)   ST = data_len
+	jmp	short .rbps_2
+.total_error_1_is_0:
+	mov	[ebx + 4], eax			; residual_bits_per_sample[1] = 0.0
+.rbps_2:
+	test	edx, edx
+	jz	.total_error_2_is_0
+	fld1					; ST = 1.0 data_len
+	mov	[esp], edx
+	mov	[esp + 4], eax			; [esp] = (FLAC__uint64)total_error_2
+	fild	qword [esp]			; ST = total_error_2 1.0 data_len
+	fdiv	st2				; ST = total_error_2/data_len 1.0 data_len
+	fldln2					; ST = ln2 total_error_2/data_len 1.0 data_len
+	fmulp	st1				; ST = ln2*total_error_2/data_len 1.0 data_len
+	fyl2x					; ST = log2(ln2*total_error_2/data_len) data_len
+	fstp	dword [ebx + 8]			; residual_bits_per_sample[2] = log2(ln2*total_error_2/data_len)   ST = data_len
+	jmp	short .rbps_3
+.total_error_2_is_0:
+	mov	[ebx + 8], eax			; residual_bits_per_sample[2] = 0.0
+.rbps_3:
+	test	esi, esi
+	jz	.total_error_3_is_0
+	fld1					; ST = 1.0 data_len
+	mov	[esp], esi
+	mov	[esp + 4], eax			; [esp] = (FLAC__uint64)total_error_3
+	fild	qword [esp]			; ST = total_error_3 1.0 data_len
+	fdiv	st2				; ST = total_error_3/data_len 1.0 data_len
+	fldln2					; ST = ln2 total_error_3/data_len 1.0 data_len
+	fmulp	st1				; ST = ln2*total_error_3/data_len 1.0 data_len
+	fyl2x					; ST = log2(ln2*total_error_3/data_len) data_len
+	fstp	dword [ebx + 12]		; residual_bits_per_sample[3] = log2(ln2*total_error_3/data_len)   ST = data_len
+	jmp	short .rbps_4
+.total_error_3_is_0:
+	mov	[ebx + 12], eax			; residual_bits_per_sample[3] = 0.0
+.rbps_4:
+	test	edi, edi
+	jz	.total_error_4_is_0
+	fld1					; ST = 1.0 data_len
+	mov	[esp], edi
+	mov	[esp + 4], eax			; [esp] = (FLAC__uint64)total_error_4
+	fild	qword [esp]			; ST = total_error_4 1.0 data_len
+	fdiv	st2				; ST = total_error_4/data_len 1.0 data_len
+	fldln2					; ST = ln2 total_error_4/data_len 1.0 data_len
+	fmulp	st1				; ST = ln2*total_error_4/data_len 1.0 data_len
+	fyl2x					; ST = log2(ln2*total_error_4/data_len) data_len
+	fstp	dword [ebx + 16]		; residual_bits_per_sample[4] = log2(ln2*total_error_4/data_len)   ST = data_len
+	jmp	short .rbps_end
+.total_error_4_is_0:
+	mov	[ebx + 16], eax			; residual_bits_per_sample[4] = 0.0
+.rbps_end:
+	fstp	st0				; ST = [empty]
+	jmp	short .end
+.data_len_is_0:
+	; data_len == 0, so residual_bits_per_sample[*] = 0.0
+	xor	ebp, ebp
+	mov	edi, [esp + 44]
+	mov	[edi], ebp
+	mov	[edi + 4], ebp
+	mov	[edi + 8], ebp
+	mov	[edi + 12], ebp
+	mov	[edi + 16], ebp
+	add	ebp, byte 4			; order = 4
+
+.end:
+	mov	eax, ebp			; return order
+	add	esp, byte 16
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+
+; end
diff --git a/src/libFLAC/ia32/lpc_asm-unrolled.nasm b/src/libFLAC/ia32/lpc_asm-unrolled.nasm
new file mode 100644
index 0000000..02c0363
--- /dev/null
+++ b/src/libFLAC/ia32/lpc_asm-unrolled.nasm
@@ -0,0 +1,785 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001-2009  Josh Coalson
+;  Copyright (C) 2011-2016  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.
+
+; [CR] is a note to flag that the instruction can be easily reordered
+
+%include "nasm.h"
+
+	data_section
+
+cglobal FLAC__lpc_compute_autocorrelation_asm
+
+	code_section
+
+; **********************************************************************
+;
+; void FLAC__lpc_compute_autocorrelation_asm(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
+; {
+;	FLAC__real d;
+;	unsigned sample, coeff;
+;	const unsigned limit = data_len - lag;
+;
+;	assert(lag > 0);
+;	assert(lag <= data_len);
+;
+;	for(coeff = 0; coeff < lag; coeff++)
+;		autoc[coeff] = 0.0;
+;	for(sample = 0; sample <= limit; sample++){
+;		d = data[sample];
+;		for(coeff = 0; coeff < lag; coeff++)
+;			autoc[coeff] += d * data[sample+coeff];
+;	}
+;	for(; sample < data_len; sample++){
+;		d = data[sample];
+;		for(coeff = 0; coeff < data_len - sample; coeff++)
+;			autoc[coeff] += d * data[sample+coeff];
+;	}
+; }
+;
+FLAC__lpc_compute_autocorrelation_asm:
+
+	push	ebp
+	lea	ebp, [esp + 8]
+	push	ebx
+	push	esi
+	push	edi
+
+	mov	edx, [ebp + 8]			; edx == lag
+	mov	ecx, [ebp + 4]			; ecx == data_len
+	mov	esi, [ebp]			; esi == data
+	mov	edi, [ebp + 12]			; edi == autoc
+
+	cmp	edx, 1
+	ja	short .lag_above_1
+.lag_eq_1:
+	fldz					; will accumulate autoc[0]
+	ALIGN 16
+.lag_1_loop:
+	fld	dword [esi]
+	add	esi, byte 4			; sample++
+	fmul	st0, st0
+	faddp	st1, st0
+	dec	ecx
+	jnz	.lag_1_loop
+	fstp	dword [edi]
+	jmp	.end
+
+.lag_above_1:
+	cmp	edx, 2
+	ja	short .lag_above_2
+.lag_eq_2:
+	fldz					; will accumulate autoc[1]
+	dec	ecx
+	fldz					; will accumulate autoc[0]
+	fld	dword [esi]
+	ALIGN 16
+.lag_2_loop:
+	add	esi, byte 4			; [CR] sample++
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi]
+	fmul	st1, st0
+	fxch
+	faddp	st3, st0			; add to autoc[1]
+	dec	ecx
+	jnz	.lag_2_loop
+	; clean up the leftovers
+	fmul	st0, st0
+	faddp	st1, st0			; add to autoc[0]
+	fstp	dword [edi]
+	fstp	dword [edi + 4]
+	jmp	.end
+
+.lag_above_2:
+	cmp	edx, 3
+	ja	short .lag_above_3
+.lag_eq_3:
+	fldz					; will accumulate autoc[2]
+	dec	ecx
+	fldz					; will accumulate autoc[1]
+	dec	ecx
+	fldz					; will accumulate autoc[0]
+	ALIGN 16
+.lag_3_loop:
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st3, st0			; add to autoc[2]
+	dec	ecx
+	jnz	.lag_3_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st1, st0
+	fxch
+	faddp	st3, st0			; add to autoc[1]
+	fmul	st0, st0
+	faddp	st1, st0			; add to autoc[0]
+	fstp	dword [edi]
+	fstp	dword [edi + 4]
+	fstp	dword [edi + 8]
+	jmp	.end
+
+.lag_above_3:
+	cmp	edx, 4
+	ja	near .lag_above_4
+.lag_eq_4:
+	fldz					; will accumulate autoc[3]
+	dec	ecx
+	fldz					; will accumulate autoc[2]
+	dec	ecx
+	fldz					; will accumulate autoc[1]
+	dec	ecx
+	fldz					; will accumulate autoc[0]
+	ALIGN 16
+.lag_4_loop:
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[2]
+	fld	dword [esi + 12]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st4, st0			; add to autoc[3]
+	dec	ecx
+	jnz	.lag_4_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st3, st0			; add to autoc[2]
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st1, st0
+	fxch
+	faddp	st3, st0			; add to autoc[1]
+	fmul	st0, st0
+	faddp	st1, st0			; add to autoc[0]
+	fstp	dword [edi]
+	fstp	dword [edi + 4]
+	fstp	dword [edi + 8]
+	fstp	dword [edi + 12]
+	jmp	.end
+
+.lag_above_4:
+	cmp	edx, 5
+	ja	near .lag_above_5
+.lag_eq_5:
+	fldz					; will accumulate autoc[4]
+	fldz					; will accumulate autoc[3]
+	fldz					; will accumulate autoc[2]
+	fldz					; will accumulate autoc[1]
+	fldz					; will accumulate autoc[0]
+	sub	ecx, byte 4
+	ALIGN 16
+.lag_5_loop:
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[2]
+	fld	dword [esi + 12]
+	fmul	st0, st1
+	faddp	st5, st0			; add to autoc[3]
+	fld	dword [esi + 16]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st5, st0			; add to autoc[4]
+	dec	ecx
+	jnz	.lag_5_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[2]
+	fld	dword [esi + 12]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st4, st0			; add to autoc[3]
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st3, st0			; add to autoc[2]
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st1, st0
+	fxch
+	faddp	st3, st0			; add to autoc[1]
+	fmul	st0, st0
+	faddp	st1, st0			; add to autoc[0]
+	fstp	dword [edi]
+	fstp	dword [edi + 4]
+	fstp	dword [edi + 8]
+	fstp	dword [edi + 12]
+	fstp	dword [edi + 16]
+	jmp	.end
+
+.lag_above_5:
+	cmp	edx, 6
+	ja	.lag_above_6
+.lag_eq_6:
+	fldz					; will accumulate autoc[5]
+	fldz					; will accumulate autoc[4]
+	fldz					; will accumulate autoc[3]
+	fldz					; will accumulate autoc[2]
+	fldz					; will accumulate autoc[1]
+	fldz					; will accumulate autoc[0]
+	sub	ecx, byte 5
+	ALIGN 16
+.lag_6_loop:
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[2]
+	fld	dword [esi + 12]
+	fmul	st0, st1
+	faddp	st5, st0			; add to autoc[3]
+	fld	dword [esi + 16]
+	fmul	st0, st1
+	faddp	st6, st0			; add to autoc[4]
+	fld	dword [esi + 20]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st6, st0			; add to autoc[5]
+	dec	ecx
+	jnz	.lag_6_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[2]
+	fld	dword [esi + 12]
+	fmul	st0, st1
+	faddp	st5, st0			; add to autoc[3]
+	fld	dword [esi + 16]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st5, st0			; add to autoc[4]
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[2]
+	fld	dword [esi + 12]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st4, st0			; add to autoc[3]
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[1]
+	fld	dword [esi + 8]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st3, st0			; add to autoc[2]
+	fld	dword [esi]
+	fld	st0
+	fmul	st0, st0
+	faddp	st2, st0			; add to autoc[0]
+	fld	dword [esi + 4]
+	fmul	st1, st0
+	fxch
+	faddp	st3, st0			; add to autoc[1]
+	fmul	st0, st0
+	faddp	st1, st0			; add to autoc[0]
+	fstp	dword [edi]
+	fstp	dword [edi + 4]
+	fstp	dword [edi + 8]
+	fstp	dword [edi + 12]
+	fstp	dword [edi + 16]
+	fstp	dword [edi + 20]
+	jmp	.end
+
+.lag_above_6:
+	;	for(coeff = 0; coeff < lag; coeff++)
+	;		autoc[coeff] = 0.0;
+	lea	ecx, [edx * 2]			; ecx = # of dwords of 0 to write
+	xor	eax, eax
+	rep	stosd
+	mov	ecx, [ebp + 4]			; ecx == data_len
+	mov	edi, [ebp + 12]			; edi == autoc
+	;	const unsigned limit = data_len - lag;
+	sub	ecx, edx
+	inc	ecx				; we are looping <= limit so we add one to the counter
+	;	for(sample = 0; sample <= limit; sample++){
+	;		d = data[sample];
+	;		for(coeff = 0; coeff < lag; coeff++)
+	;			autoc[coeff] += d * data[sample+coeff];
+	;	}
+	xor	eax, eax			; eax == sample <- 0
+	ALIGN 16
+.outer_loop:
+	push	eax				; save sample
+	fld	dword [esi + eax * 4]		; ST = d <- data[sample]
+	mov	ebx, eax			; ebx == sample+coeff <- sample
+	mov	edx, [ebp + 8]			; edx <- lag
+	xor	eax, eax			; eax == coeff <- 0
+	ALIGN 16
+.inner_loop:
+	fld	st0				; ST = d d
+	fmul	dword [esi + ebx * 4]		; ST = d*data[sample+coeff] d
+	fadd	dword [edi + eax * 4]		; ST = autoc[coeff]+d*data[sample+coeff] d
+	fstp	dword [edi + eax * 4]		; autoc[coeff]+=d*data[sample+coeff]  ST = d
+	inc	ebx				; (sample+coeff)++
+	inc	eax				; coeff++
+	dec	edx
+	jnz	.inner_loop
+	pop	eax				; restore sample
+	fstp	st0				; pop d, ST = empty
+	inc	eax				; sample++
+	loop	.outer_loop
+	;	for(; sample < data_len; sample++){
+	;		d = data[sample];
+	;		for(coeff = 0; coeff < data_len - sample; coeff++)
+	;			autoc[coeff] += d * data[sample+coeff];
+	;	}
+	mov	ecx, [ebp + 8]			; ecx <- lag
+	dec	ecx				; ecx <- lag - 1
+	jz	.outer_end			; skip loop if 0
+.outer_loop2:
+	push	eax				; save sample
+	fld	dword [esi + eax * 4]		; ST = d <- data[sample]
+	mov	ebx, eax			; ebx == sample+coeff <- sample
+	mov	edx, [ebp + 4]			; edx <- data_len
+	sub	edx, eax			; edx <- data_len-sample
+	xor	eax, eax			; eax == coeff <- 0
+.inner_loop2:
+	fld	st0				; ST = d d
+	fmul	dword [esi + ebx * 4]		; ST = d*data[sample+coeff] d
+	fadd	dword [edi + eax * 4]		; ST = autoc[coeff]+d*data[sample+coeff] d
+	fstp	dword [edi + eax * 4]		; autoc[coeff]+=d*data[sample+coeff]  ST = d
+	inc	ebx				; (sample+coeff)++
+	inc	eax				; coeff++
+	dec	edx
+	jnz	.inner_loop2
+	pop	eax				; restore sample
+	fstp	st0				; pop d, ST = empty
+	inc	eax				; sample++
+	loop	.outer_loop2
+.outer_end:
+	jmp	.end
+
+.lag_eq_6_plus_1:
+	mov	ecx, [ebp + 4]			; ecx == data_len
+	mov	esi, [ebp]			; esi == data
+	mov	edi, [ebp + 12]			; edi == autoc
+	fldz					; will accumulate autoc[6]
+	sub	ecx, byte 6
+	ALIGN 16
+.lag_6_1_loop:
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st1, st0			; add to autoc[6]
+	dec	ecx
+	jnz	.lag_6_1_loop
+	fstp	dword [edi + 24]
+	jmp	.end
+
+.lag_eq_6_plus_2:
+	mov	ecx, [ebp + 4]			; ecx == data_len
+	mov	esi, [ebp]			; esi == data
+	mov	edi, [ebp + 12]			; edi == autoc
+	fldz					; will accumulate autoc[7]
+	fldz					; will accumulate autoc[6]
+	sub	ecx, byte 7
+	ALIGN 16
+.lag_6_2_loop:
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st2, st0			; add to autoc[7]
+	dec	ecx
+	jnz	.lag_6_2_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmulp	st1, st0
+	faddp	st1, st0			; add to autoc[6]
+	fstp	dword [edi + 24]
+	fstp	dword [edi + 28]
+	jmp	.end
+
+.lag_eq_6_plus_3:
+	mov	ecx, [ebp + 4]			; ecx == data_len
+	mov	esi, [ebp]			; esi == data
+	mov	edi, [ebp + 12]			; edi == autoc
+	fldz					; will accumulate autoc[8]
+	fldz					; will accumulate autoc[7]
+	fldz					; will accumulate autoc[6]
+	sub	ecx, byte 8
+	ALIGN 16
+.lag_6_3_loop:
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st3, st0			; add to autoc[8]
+	dec	ecx
+	jnz	.lag_6_3_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st2, st0			; add to autoc[7]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmulp	st1, st0
+	faddp	st1, st0			; add to autoc[6]
+	fstp	dword [edi + 24]
+	fstp	dword [edi + 28]
+	fstp	dword [edi + 32]
+	jmp	.end
+
+.lag_eq_6_plus_4:
+	mov	ecx, [ebp + 4]			; ecx == data_len
+	mov	esi, [ebp]			; esi == data
+	mov	edi, [ebp + 12]			; edi == autoc
+	fldz					; will accumulate autoc[9]
+	fldz					; will accumulate autoc[8]
+	fldz					; will accumulate autoc[7]
+	fldz					; will accumulate autoc[6]
+	sub	ecx, byte 9
+	ALIGN 16
+.lag_6_4_loop:
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[8]
+	fld	dword [esi + 36]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st4, st0			; add to autoc[9]
+	dec	ecx
+	jnz	.lag_6_4_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st3, st0			; add to autoc[8]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st2, st0			; add to autoc[7]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmulp	st1, st0
+	faddp	st1, st0			; add to autoc[6]
+	fstp	dword [edi + 24]
+	fstp	dword [edi + 28]
+	fstp	dword [edi + 32]
+	fstp	dword [edi + 36]
+	jmp	.end
+
+.lag_eq_6_plus_5:
+	mov	ecx, [ebp + 4]			; ecx == data_len
+	mov	esi, [ebp]			; esi == data
+	mov	edi, [ebp + 12]			; edi == autoc
+	fldz					; will accumulate autoc[10]
+	fldz					; will accumulate autoc[9]
+	fldz					; will accumulate autoc[8]
+	fldz					; will accumulate autoc[7]
+	fldz					; will accumulate autoc[6]
+	sub	ecx, byte 10
+	ALIGN 16
+.lag_6_5_loop:
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[8]
+	fld	dword [esi + 36]
+	fmul	st0, st1
+	faddp	st5, st0			; add to autoc[9]
+	fld	dword [esi + 40]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st5, st0			; add to autoc[10]
+	dec	ecx
+	jnz	.lag_6_5_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[8]
+	fld	dword [esi + 36]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st4, st0			; add to autoc[9]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st3, st0			; add to autoc[8]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st2, st0			; add to autoc[7]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmulp	st1, st0
+	faddp	st1, st0			; add to autoc[6]
+	fstp	dword [edi + 24]
+	fstp	dword [edi + 28]
+	fstp	dword [edi + 32]
+	fstp	dword [edi + 36]
+	fstp	dword [edi + 40]
+	jmp	.end
+
+.lag_eq_6_plus_6:
+	mov	ecx, [ebp + 4]			; ecx == data_len
+	mov	esi, [ebp]			; esi == data
+	mov	edi, [ebp + 12]			; edi == autoc
+	fldz					; will accumulate autoc[11]
+	fldz					; will accumulate autoc[10]
+	fldz					; will accumulate autoc[9]
+	fldz					; will accumulate autoc[8]
+	fldz					; will accumulate autoc[7]
+	fldz					; will accumulate autoc[6]
+	sub	ecx, byte 11
+	ALIGN 16
+.lag_6_6_loop:
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[8]
+	fld	dword [esi + 36]
+	fmul	st0, st1
+	faddp	st5, st0			; add to autoc[9]
+	fld	dword [esi + 40]
+	fmul	st0, st1
+	faddp	st6, st0			; add to autoc[10]
+	fld	dword [esi + 44]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st6, st0			; add to autoc[11]
+	dec	ecx
+	jnz	.lag_6_6_loop
+	; clean up the leftovers
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[8]
+	fld	dword [esi + 36]
+	fmul	st0, st1
+	faddp	st5, st0			; add to autoc[9]
+	fld	dword [esi + 40]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st5, st0			; add to autoc[10]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmul	st0, st1
+	faddp	st4, st0			; add to autoc[8]
+	fld	dword [esi + 36]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st4, st0			; add to autoc[9]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmul	st0, st1
+	faddp	st3, st0			; add to autoc[7]
+	fld	dword [esi + 32]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st3, st0			; add to autoc[8]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmul	st0, st1
+	faddp	st2, st0			; add to autoc[6]
+	fld	dword [esi + 28]
+	fmulp	st1, st0
+	add	esi, byte 4			; [CR] sample++
+	faddp	st2, st0			; add to autoc[7]
+	fld	dword [esi]
+	fld	dword [esi + 24]
+	fmulp	st1, st0
+	faddp	st1, st0			; add to autoc[6]
+	fstp	dword [edi + 24]
+	fstp	dword [edi + 28]
+	fstp	dword [edi + 32]
+	fstp	dword [edi + 36]
+	fstp	dword [edi + 40]
+	fstp	dword [edi + 44]
+	jmp	.end
+
+.end:
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+
+; end
diff --git a/src/libFLAC/ia32/lpc_asm.nasm b/src/libFLAC/ia32/lpc_asm.nasm
new file mode 100644
index 0000000..272fb7b
--- /dev/null
+++ b/src/libFLAC/ia32/lpc_asm.nasm
@@ -0,0 +1,2049 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001-2009  Josh Coalson
+;  Copyright (C) 2011-2016  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 "nasm.h"
+
+	data_section
+
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old
+cglobal FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32
+cglobal FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx
+cglobal FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32
+cglobal FLAC__lpc_restore_signal_asm_ia32
+cglobal FLAC__lpc_restore_signal_asm_ia32_mmx
+cglobal FLAC__lpc_restore_signal_wide_asm_ia32
+
+	code_section
+
+; **********************************************************************
+;
+; void FLAC__lpc_compute_autocorrelation_asm(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
+; {
+;	FLAC__real d;
+;	unsigned sample, coeff;
+;	const unsigned limit = data_len - lag;
+;
+;	FLAC__ASSERT(lag > 0);
+;	FLAC__ASSERT(lag <= data_len);
+;
+;	for(coeff = 0; coeff < lag; coeff++)
+;		autoc[coeff] = 0.0;
+;	for(sample = 0; sample <= limit; sample++) {
+;		d = data[sample];
+;		for(coeff = 0; coeff < lag; coeff++)
+;			autoc[coeff] += d * data[sample+coeff];
+;	}
+;	for(; sample < data_len; sample++) {
+;		d = data[sample];
+;		for(coeff = 0; coeff < data_len - sample; coeff++)
+;			autoc[coeff] += d * data[sample+coeff];
+;	}
+; }
+;
+	ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32
+	;[esp + 28] == autoc[]
+	;[esp + 24] == lag
+	;[esp + 20] == data_len
+	;[esp + 16] == data[]
+
+	;ASSERT(lag > 0)
+	;ASSERT(lag <= 33)
+	;ASSERT(lag <= data_len)
+
+.begin:
+	push	esi
+	push	edi
+	push	ebx
+
+	;	for(coeff = 0; coeff < lag; coeff++)
+	;		autoc[coeff] = 0.0;
+	mov	edi, [esp + 28]			; edi == autoc
+	mov	ecx, [esp + 24]			; ecx = # of dwords (=lag) of 0 to write
+	xor	eax, eax
+	rep	stosd
+
+	;	const unsigned limit = data_len - lag;
+	mov	eax, [esp + 24]			; eax == lag
+	mov	ecx, [esp + 20]
+	sub	ecx, eax			; ecx == limit
+
+	mov	edi, [esp + 28]			; edi == autoc
+	mov	esi, [esp + 16]			; esi == data
+	inc	ecx				; we are looping <= limit so we add one to the counter
+
+	;	for(sample = 0; sample <= limit; sample++) {
+	;		d = data[sample];
+	;		for(coeff = 0; coeff < lag; coeff++)
+	;			autoc[coeff] += d * data[sample+coeff];
+	;	}
+	fld	dword [esi]			; ST = d <- data[sample]
+	; each iteration is 11 bytes so we need (-eax)*11, so we do (-12*eax + eax)
+	lea	edx, [eax + eax*2]
+	neg	edx
+	lea	edx, [eax + edx*4 + .jumper1_0 - .get_eip1]
+	call	.mov_eip_to_ebx
+.get_eip1:
+	add	edx, ebx
+	inc	edx				; compensate for the shorter opcode on the last iteration
+	inc	edx				; compensate for the shorter opcode on the last iteration
+	inc	edx				; compensate for the shorter opcode on the last iteration
+	cmp	eax, 33
+	jne	.loop1_start
+	sub	edx, byte 9			; compensate for the longer opcodes on the first iteration
+.loop1_start:
+	jmp	edx
+
+.mov_eip_to_ebx:
+	mov	ebx, [esp]
+	ret
+
+	fld	st0				; ST = d d
+	fmul	dword [esi + (32*4)]		; ST = d*data[sample+32] d		WATCHOUT: not a byte displacement here!
+	fadd	dword [edi + (32*4)]		; ST = autoc[32]+d*data[sample+32] d	WATCHOUT: not a byte displacement here!
+	fstp	dword [edi + (32*4)]		; autoc[32]+=d*data[sample+32]  ST = d	WATCHOUT: not a byte displacement here!
+	fld	st0				; ST = d d
+	fmul	dword [esi + (31*4)]		; ST = d*data[sample+31] d
+	fadd	dword [edi + (31*4)]		; ST = autoc[31]+d*data[sample+31] d
+	fstp	dword [edi + (31*4)]		; autoc[31]+=d*data[sample+31]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (30*4)]		; ST = d*data[sample+30] d
+	fadd	dword [edi + (30*4)]		; ST = autoc[30]+d*data[sample+30] d
+	fstp	dword [edi + (30*4)]		; autoc[30]+=d*data[sample+30]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (29*4)]		; ST = d*data[sample+29] d
+	fadd	dword [edi + (29*4)]		; ST = autoc[29]+d*data[sample+29] d
+	fstp	dword [edi + (29*4)]		; autoc[29]+=d*data[sample+29]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (28*4)]		; ST = d*data[sample+28] d
+	fadd	dword [edi + (28*4)]		; ST = autoc[28]+d*data[sample+28] d
+	fstp	dword [edi + (28*4)]		; autoc[28]+=d*data[sample+28]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (27*4)]		; ST = d*data[sample+27] d
+	fadd	dword [edi + (27*4)]		; ST = autoc[27]+d*data[sample+27] d
+	fstp	dword [edi + (27*4)]		; autoc[27]+=d*data[sample+27]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (26*4)]		; ST = d*data[sample+26] d
+	fadd	dword [edi + (26*4)]		; ST = autoc[26]+d*data[sample+26] d
+	fstp	dword [edi + (26*4)]		; autoc[26]+=d*data[sample+26]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (25*4)]		; ST = d*data[sample+25] d
+	fadd	dword [edi + (25*4)]		; ST = autoc[25]+d*data[sample+25] d
+	fstp	dword [edi + (25*4)]		; autoc[25]+=d*data[sample+25]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (24*4)]		; ST = d*data[sample+24] d
+	fadd	dword [edi + (24*4)]		; ST = autoc[24]+d*data[sample+24] d
+	fstp	dword [edi + (24*4)]		; autoc[24]+=d*data[sample+24]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (23*4)]		; ST = d*data[sample+23] d
+	fadd	dword [edi + (23*4)]		; ST = autoc[23]+d*data[sample+23] d
+	fstp	dword [edi + (23*4)]		; autoc[23]+=d*data[sample+23]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (22*4)]		; ST = d*data[sample+22] d
+	fadd	dword [edi + (22*4)]		; ST = autoc[22]+d*data[sample+22] d
+	fstp	dword [edi + (22*4)]		; autoc[22]+=d*data[sample+22]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (21*4)]		; ST = d*data[sample+21] d
+	fadd	dword [edi + (21*4)]		; ST = autoc[21]+d*data[sample+21] d
+	fstp	dword [edi + (21*4)]		; autoc[21]+=d*data[sample+21]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (20*4)]		; ST = d*data[sample+20] d
+	fadd	dword [edi + (20*4)]		; ST = autoc[20]+d*data[sample+20] d
+	fstp	dword [edi + (20*4)]		; autoc[20]+=d*data[sample+20]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (19*4)]		; ST = d*data[sample+19] d
+	fadd	dword [edi + (19*4)]		; ST = autoc[19]+d*data[sample+19] d
+	fstp	dword [edi + (19*4)]		; autoc[19]+=d*data[sample+19]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (18*4)]		; ST = d*data[sample+18] d
+	fadd	dword [edi + (18*4)]		; ST = autoc[18]+d*data[sample+18] d
+	fstp	dword [edi + (18*4)]		; autoc[18]+=d*data[sample+18]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (17*4)]		; ST = d*data[sample+17] d
+	fadd	dword [edi + (17*4)]		; ST = autoc[17]+d*data[sample+17] d
+	fstp	dword [edi + (17*4)]		; autoc[17]+=d*data[sample+17]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (16*4)]		; ST = d*data[sample+16] d
+	fadd	dword [edi + (16*4)]		; ST = autoc[16]+d*data[sample+16] d
+	fstp	dword [edi + (16*4)]		; autoc[16]+=d*data[sample+16]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (15*4)]		; ST = d*data[sample+15] d
+	fadd	dword [edi + (15*4)]		; ST = autoc[15]+d*data[sample+15] d
+	fstp	dword [edi + (15*4)]		; autoc[15]+=d*data[sample+15]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (14*4)]		; ST = d*data[sample+14] d
+	fadd	dword [edi + (14*4)]		; ST = autoc[14]+d*data[sample+14] d
+	fstp	dword [edi + (14*4)]		; autoc[14]+=d*data[sample+14]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (13*4)]		; ST = d*data[sample+13] d
+	fadd	dword [edi + (13*4)]		; ST = autoc[13]+d*data[sample+13] d
+	fstp	dword [edi + (13*4)]		; autoc[13]+=d*data[sample+13]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (12*4)]		; ST = d*data[sample+12] d
+	fadd	dword [edi + (12*4)]		; ST = autoc[12]+d*data[sample+12] d
+	fstp	dword [edi + (12*4)]		; autoc[12]+=d*data[sample+12]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (11*4)]		; ST = d*data[sample+11] d
+	fadd	dword [edi + (11*4)]		; ST = autoc[11]+d*data[sample+11] d
+	fstp	dword [edi + (11*4)]		; autoc[11]+=d*data[sample+11]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (10*4)]		; ST = d*data[sample+10] d
+	fadd	dword [edi + (10*4)]		; ST = autoc[10]+d*data[sample+10] d
+	fstp	dword [edi + (10*4)]		; autoc[10]+=d*data[sample+10]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 9*4)]		; ST = d*data[sample+9] d
+	fadd	dword [edi + ( 9*4)]		; ST = autoc[9]+d*data[sample+9] d
+	fstp	dword [edi + ( 9*4)]		; autoc[9]+=d*data[sample+9]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 8*4)]		; ST = d*data[sample+8] d
+	fadd	dword [edi + ( 8*4)]		; ST = autoc[8]+d*data[sample+8] d
+	fstp	dword [edi + ( 8*4)]		; autoc[8]+=d*data[sample+8]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 7*4)]		; ST = d*data[sample+7] d
+	fadd	dword [edi + ( 7*4)]		; ST = autoc[7]+d*data[sample+7] d
+	fstp	dword [edi + ( 7*4)]		; autoc[7]+=d*data[sample+7]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 6*4)]		; ST = d*data[sample+6] d
+	fadd	dword [edi + ( 6*4)]		; ST = autoc[6]+d*data[sample+6] d
+	fstp	dword [edi + ( 6*4)]		; autoc[6]+=d*data[sample+6]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 5*4)]		; ST = d*data[sample+4] d
+	fadd	dword [edi + ( 5*4)]		; ST = autoc[4]+d*data[sample+4] d
+	fstp	dword [edi + ( 5*4)]		; autoc[4]+=d*data[sample+4]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 4*4)]		; ST = d*data[sample+4] d
+	fadd	dword [edi + ( 4*4)]		; ST = autoc[4]+d*data[sample+4] d
+	fstp	dword [edi + ( 4*4)]		; autoc[4]+=d*data[sample+4]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 3*4)]		; ST = d*data[sample+3] d
+	fadd	dword [edi + ( 3*4)]		; ST = autoc[3]+d*data[sample+3] d
+	fstp	dword [edi + ( 3*4)]		; autoc[3]+=d*data[sample+3]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 2*4)]		; ST = d*data[sample+2] d
+	fadd	dword [edi + ( 2*4)]		; ST = autoc[2]+d*data[sample+2] d
+	fstp	dword [edi + ( 2*4)]		; autoc[2]+=d*data[sample+2]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 1*4)]		; ST = d*data[sample+1] d
+	fadd	dword [edi + ( 1*4)]		; ST = autoc[1]+d*data[sample+1] d
+	fstp	dword [edi + ( 1*4)]		; autoc[1]+=d*data[sample+1]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi]			; ST = d*data[sample] d			WATCHOUT: no displacement byte here!
+	fadd	dword [edi]			; ST = autoc[0]+d*data[sample] d	WATCHOUT: no displacement byte here!
+	fstp	dword [edi]			; autoc[0]+=d*data[sample]  ST = d	WATCHOUT: no displacement byte here!
+.jumper1_0:
+
+	fstp	st0				; pop d, ST = empty
+	add	esi, byte 4			; sample++
+	dec	ecx
+	jz	.loop1_end
+	fld	dword [esi]			; ST = d <- data[sample]
+	jmp	edx
+.loop1_end:
+
+	;	for(; sample < data_len; sample++) {
+	;		d = data[sample];
+	;		for(coeff = 0; coeff < data_len - sample; coeff++)
+	;			autoc[coeff] += d * data[sample+coeff];
+	;	}
+	mov	ecx, [esp + 24]			; ecx <- lag
+	dec	ecx				; ecx <- lag - 1
+	jz	near .end			; skip loop if 0 (i.e. lag == 1)
+
+	fld	dword [esi]			; ST = d <- data[sample]
+	mov	eax, ecx			; eax <- lag - 1 == data_len - sample the first time through
+	; each iteration is 11 bytes so we need (-eax)*11, so we do (-12*eax + eax)
+	lea	edx, [eax + eax*2]
+	neg	edx
+	lea	edx, [eax + edx*4 + .jumper2_0 - .get_eip2]
+	call	.mov_eip_to_ebx
+.get_eip2:
+	add	edx, ebx
+	inc	edx				; compensate for the shorter opcode on the last iteration
+	inc	edx				; compensate for the shorter opcode on the last iteration
+	inc	edx				; compensate for the shorter opcode on the last iteration
+	jmp	edx
+
+	fld	st0				; ST = d d
+	fmul	dword [esi + (31*4)]		; ST = d*data[sample+31] d
+	fadd	dword [edi + (31*4)]		; ST = autoc[31]+d*data[sample+31] d
+	fstp	dword [edi + (31*4)]		; autoc[31]+=d*data[sample+31]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (30*4)]		; ST = d*data[sample+30] d
+	fadd	dword [edi + (30*4)]		; ST = autoc[30]+d*data[sample+30] d
+	fstp	dword [edi + (30*4)]		; autoc[30]+=d*data[sample+30]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (29*4)]		; ST = d*data[sample+29] d
+	fadd	dword [edi + (29*4)]		; ST = autoc[29]+d*data[sample+29] d
+	fstp	dword [edi + (29*4)]		; autoc[29]+=d*data[sample+29]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (28*4)]		; ST = d*data[sample+28] d
+	fadd	dword [edi + (28*4)]		; ST = autoc[28]+d*data[sample+28] d
+	fstp	dword [edi + (28*4)]		; autoc[28]+=d*data[sample+28]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (27*4)]		; ST = d*data[sample+27] d
+	fadd	dword [edi + (27*4)]		; ST = autoc[27]+d*data[sample+27] d
+	fstp	dword [edi + (27*4)]		; autoc[27]+=d*data[sample+27]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (26*4)]		; ST = d*data[sample+26] d
+	fadd	dword [edi + (26*4)]		; ST = autoc[26]+d*data[sample+26] d
+	fstp	dword [edi + (26*4)]		; autoc[26]+=d*data[sample+26]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (25*4)]		; ST = d*data[sample+25] d
+	fadd	dword [edi + (25*4)]		; ST = autoc[25]+d*data[sample+25] d
+	fstp	dword [edi + (25*4)]		; autoc[25]+=d*data[sample+25]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (24*4)]		; ST = d*data[sample+24] d
+	fadd	dword [edi + (24*4)]		; ST = autoc[24]+d*data[sample+24] d
+	fstp	dword [edi + (24*4)]		; autoc[24]+=d*data[sample+24]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (23*4)]		; ST = d*data[sample+23] d
+	fadd	dword [edi + (23*4)]		; ST = autoc[23]+d*data[sample+23] d
+	fstp	dword [edi + (23*4)]		; autoc[23]+=d*data[sample+23]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (22*4)]		; ST = d*data[sample+22] d
+	fadd	dword [edi + (22*4)]		; ST = autoc[22]+d*data[sample+22] d
+	fstp	dword [edi + (22*4)]		; autoc[22]+=d*data[sample+22]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (21*4)]		; ST = d*data[sample+21] d
+	fadd	dword [edi + (21*4)]		; ST = autoc[21]+d*data[sample+21] d
+	fstp	dword [edi + (21*4)]		; autoc[21]+=d*data[sample+21]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (20*4)]		; ST = d*data[sample+20] d
+	fadd	dword [edi + (20*4)]		; ST = autoc[20]+d*data[sample+20] d
+	fstp	dword [edi + (20*4)]		; autoc[20]+=d*data[sample+20]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (19*4)]		; ST = d*data[sample+19] d
+	fadd	dword [edi + (19*4)]		; ST = autoc[19]+d*data[sample+19] d
+	fstp	dword [edi + (19*4)]		; autoc[19]+=d*data[sample+19]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (18*4)]		; ST = d*data[sample+18] d
+	fadd	dword [edi + (18*4)]		; ST = autoc[18]+d*data[sample+18] d
+	fstp	dword [edi + (18*4)]		; autoc[18]+=d*data[sample+18]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (17*4)]		; ST = d*data[sample+17] d
+	fadd	dword [edi + (17*4)]		; ST = autoc[17]+d*data[sample+17] d
+	fstp	dword [edi + (17*4)]		; autoc[17]+=d*data[sample+17]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (16*4)]		; ST = d*data[sample+16] d
+	fadd	dword [edi + (16*4)]		; ST = autoc[16]+d*data[sample+16] d
+	fstp	dword [edi + (16*4)]		; autoc[16]+=d*data[sample+16]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (15*4)]		; ST = d*data[sample+15] d
+	fadd	dword [edi + (15*4)]		; ST = autoc[15]+d*data[sample+15] d
+	fstp	dword [edi + (15*4)]		; autoc[15]+=d*data[sample+15]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (14*4)]		; ST = d*data[sample+14] d
+	fadd	dword [edi + (14*4)]		; ST = autoc[14]+d*data[sample+14] d
+	fstp	dword [edi + (14*4)]		; autoc[14]+=d*data[sample+14]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (13*4)]		; ST = d*data[sample+13] d
+	fadd	dword [edi + (13*4)]		; ST = autoc[13]+d*data[sample+13] d
+	fstp	dword [edi + (13*4)]		; autoc[13]+=d*data[sample+13]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (12*4)]		; ST = d*data[sample+12] d
+	fadd	dword [edi + (12*4)]		; ST = autoc[12]+d*data[sample+12] d
+	fstp	dword [edi + (12*4)]		; autoc[12]+=d*data[sample+12]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (11*4)]		; ST = d*data[sample+11] d
+	fadd	dword [edi + (11*4)]		; ST = autoc[11]+d*data[sample+11] d
+	fstp	dword [edi + (11*4)]		; autoc[11]+=d*data[sample+11]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + (10*4)]		; ST = d*data[sample+10] d
+	fadd	dword [edi + (10*4)]		; ST = autoc[10]+d*data[sample+10] d
+	fstp	dword [edi + (10*4)]		; autoc[10]+=d*data[sample+10]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 9*4)]		; ST = d*data[sample+9] d
+	fadd	dword [edi + ( 9*4)]		; ST = autoc[9]+d*data[sample+9] d
+	fstp	dword [edi + ( 9*4)]		; autoc[9]+=d*data[sample+9]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 8*4)]		; ST = d*data[sample+8] d
+	fadd	dword [edi + ( 8*4)]		; ST = autoc[8]+d*data[sample+8] d
+	fstp	dword [edi + ( 8*4)]		; autoc[8]+=d*data[sample+8]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 7*4)]		; ST = d*data[sample+7] d
+	fadd	dword [edi + ( 7*4)]		; ST = autoc[7]+d*data[sample+7] d
+	fstp	dword [edi + ( 7*4)]		; autoc[7]+=d*data[sample+7]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 6*4)]		; ST = d*data[sample+6] d
+	fadd	dword [edi + ( 6*4)]		; ST = autoc[6]+d*data[sample+6] d
+	fstp	dword [edi + ( 6*4)]		; autoc[6]+=d*data[sample+6]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 5*4)]		; ST = d*data[sample+4] d
+	fadd	dword [edi + ( 5*4)]		; ST = autoc[4]+d*data[sample+4] d
+	fstp	dword [edi + ( 5*4)]		; autoc[4]+=d*data[sample+4]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 4*4)]		; ST = d*data[sample+4] d
+	fadd	dword [edi + ( 4*4)]		; ST = autoc[4]+d*data[sample+4] d
+	fstp	dword [edi + ( 4*4)]		; autoc[4]+=d*data[sample+4]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 3*4)]		; ST = d*data[sample+3] d
+	fadd	dword [edi + ( 3*4)]		; ST = autoc[3]+d*data[sample+3] d
+	fstp	dword [edi + ( 3*4)]		; autoc[3]+=d*data[sample+3]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 2*4)]		; ST = d*data[sample+2] d
+	fadd	dword [edi + ( 2*4)]		; ST = autoc[2]+d*data[sample+2] d
+	fstp	dword [edi + ( 2*4)]		; autoc[2]+=d*data[sample+2]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi + ( 1*4)]		; ST = d*data[sample+1] d
+	fadd	dword [edi + ( 1*4)]		; ST = autoc[1]+d*data[sample+1] d
+	fstp	dword [edi + ( 1*4)]		; autoc[1]+=d*data[sample+1]  ST = d
+	fld	st0				; ST = d d
+	fmul	dword [esi]			; ST = d*data[sample] d			WATCHOUT: no displacement byte here!
+	fadd	dword [edi]			; ST = autoc[0]+d*data[sample] d	WATCHOUT: no displacement byte here!
+	fstp	dword [edi]			; autoc[0]+=d*data[sample]  ST = d	WATCHOUT: no displacement byte here!
+.jumper2_0:
+
+	fstp	st0				; pop d, ST = empty
+	add	esi, byte 4			; sample++
+	dec	ecx
+	jz	.loop2_end
+	add	edx, byte 11			; adjust our inner loop counter by adjusting the jump target
+	fld	dword [esi]			; ST = d <- data[sample]
+	jmp	edx
+.loop2_end:
+
+.end:
+	pop	ebx
+	pop	edi
+	pop	esi
+	ret
+
+	ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old
+	;[esp + 16] == autoc[]
+	;[esp + 12] == lag
+	;[esp + 8] == data_len
+	;[esp + 4] == data[]
+
+	;ASSERT(lag > 0)
+	;ASSERT(lag <= 4)
+	;ASSERT(lag <= data_len)
+
+	;	for(coeff = 0; coeff < lag; coeff++)
+	;		autoc[coeff] = 0.0;
+	xorps	xmm5, xmm5
+
+	mov	edx, [esp + 8]			; edx == data_len
+	mov	eax, [esp + 4]			; eax == &data[sample] <- &data[0]
+
+	movss	xmm0, [eax]			; xmm0 = 0,0,0,data[0]
+	add	eax, 4
+	movaps	xmm2, xmm0			; xmm2 = 0,0,0,data[0]
+	shufps	xmm0, xmm0, 0			; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+.warmup:					; xmm2 == data[sample-3],data[sample-2],data[sample-1],data[sample]
+	mulps	xmm0, xmm2			; xmm0 = xmm0 * xmm2
+	addps	xmm5, xmm0			; xmm5 += xmm0 * xmm2
+	dec	edx
+	jz	.loop_end
+	ALIGN 16
+.loop_start:
+	; start by reading the next sample
+	movss	xmm0, [eax]			; xmm0 = 0,0,0,data[sample]
+	add	eax, 4
+	shufps	xmm0, xmm0, 0			; xmm0 = data[sample],data[sample],data[sample],data[sample]
+	shufps	xmm2, xmm2, 93h			; 93h=2-1-0-3 => xmm2 gets rotated left by one float
+	movss	xmm2, xmm0
+	mulps	xmm0, xmm2			; xmm0 = xmm0 * xmm2
+	addps	xmm5, xmm0			; xmm5 += xmm0 * xmm2
+	dec	edx
+	jnz	.loop_start
+.loop_end:
+	; store autoc
+	mov	edx, [esp + 16]			; edx == autoc
+	movups	[edx], xmm5
+
+.end:
+	ret
+
+	ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old
+	;[esp + 16] == autoc[]
+	;[esp + 12] == lag
+	;[esp + 8] == data_len
+	;[esp + 4] == data[]
+
+	;ASSERT(lag > 0)
+	;ASSERT(lag <= 8)
+	;ASSERT(lag <= data_len)
+
+	;	for(coeff = 0; coeff < lag; coeff++)
+	;		autoc[coeff] = 0.0;
+	xorps	xmm5, xmm5
+	xorps	xmm6, xmm6
+
+	mov	edx, [esp + 8]			; edx == data_len
+	mov	eax, [esp + 4]			; eax == &data[sample] <- &data[0]
+
+	movss	xmm0, [eax]			; xmm0 = 0,0,0,data[0]
+	add	eax, 4
+	movaps	xmm2, xmm0			; xmm2 = 0,0,0,data[0]
+	shufps	xmm0, xmm0, 0			; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+	movaps	xmm1, xmm0			; xmm1 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+	xorps	xmm3, xmm3			; xmm3 = 0,0,0,0
+.warmup:					; xmm3:xmm2 == data[sample-7],data[sample-6],...,data[sample]
+	mulps	xmm0, xmm2
+	mulps	xmm1, xmm3			; xmm1:xmm0 = xmm1:xmm0 * xmm3:xmm2
+	addps	xmm5, xmm0
+	addps	xmm6, xmm1			; xmm6:xmm5 += xmm1:xmm0 * xmm3:xmm2
+	dec	edx
+	jz	.loop_end
+	ALIGN 16
+.loop_start:
+	; start by reading the next sample
+	movss	xmm0, [eax]			; xmm0 = 0,0,0,data[sample]
+	; here we reorder the instructions; see the (#) indexes for a logical order
+	shufps	xmm2, xmm2, 93h			; (3) 93h=2-1-0-3 => xmm2 gets rotated left by one float
+	add	eax, 4				; (0)
+	shufps	xmm3, xmm3, 93h			; (4) 93h=2-1-0-3 => xmm3 gets rotated left by one float
+	shufps	xmm0, xmm0, 0			; (1) xmm0 = data[sample],data[sample],data[sample],data[sample]
+	movss	xmm3, xmm2			; (5)
+	movaps	xmm1, xmm0			; (2) xmm1 = data[sample],data[sample],data[sample],data[sample]
+	movss	xmm2, xmm0			; (6)
+	mulps	xmm1, xmm3			; (8)
+	mulps	xmm0, xmm2			; (7) xmm1:xmm0 = xmm1:xmm0 * xmm3:xmm2
+	addps	xmm6, xmm1			; (10)
+	addps	xmm5, xmm0			; (9) xmm6:xmm5 += xmm1:xmm0 * xmm3:xmm2
+	dec	edx
+	jnz	.loop_start
+.loop_end:
+	; store autoc
+	mov	edx, [esp + 16]			; edx == autoc
+	movups	[edx], xmm5
+	movups	[edx + 16], xmm6
+
+.end:
+	ret
+
+	ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old
+	;[esp + 16] == autoc[]
+	;[esp + 12] == lag
+	;[esp + 8] == data_len
+	;[esp + 4] == data[]
+
+	;ASSERT(lag > 0)
+	;ASSERT(lag <= 12)
+	;ASSERT(lag <= data_len)
+
+	;	for(coeff = 0; coeff < lag; coeff++)
+	;		autoc[coeff] = 0.0;
+	xorps	xmm5, xmm5
+	xorps	xmm6, xmm6
+	xorps	xmm7, xmm7
+
+	mov	edx, [esp + 8]			; edx == data_len
+	mov	eax, [esp + 4]			; eax == &data[sample] <- &data[0]
+
+	movss	xmm0, [eax]			; xmm0 = 0,0,0,data[0]
+	add	eax, 4
+	movaps	xmm2, xmm0			; xmm2 = 0,0,0,data[0]
+	shufps	xmm0, xmm0, 0			; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+	xorps	xmm3, xmm3			; xmm3 = 0,0,0,0
+	xorps	xmm4, xmm4			; xmm4 = 0,0,0,0
+.warmup:					; xmm3:xmm2 == data[sample-7],data[sample-6],...,data[sample]
+	movaps	xmm1, xmm0
+	mulps	xmm1, xmm2
+	addps	xmm5, xmm1
+	movaps	xmm1, xmm0
+	mulps	xmm1, xmm3
+	addps	xmm6, xmm1
+	mulps	xmm0, xmm4
+	addps	xmm7, xmm0			; xmm7:xmm6:xmm5 += xmm0:xmm0:xmm0 * xmm4:xmm3:xmm2
+	dec	edx
+	jz	.loop_end
+	ALIGN 16
+.loop_start:
+	; start by reading the next sample
+	movss	xmm0, [eax]			; xmm0 = 0,0,0,data[sample]
+	add	eax, 4
+	shufps	xmm0, xmm0, 0			; xmm0 = data[sample],data[sample],data[sample],data[sample]
+
+	; shift xmm4:xmm3:xmm2 left by one float
+	shufps	xmm2, xmm2, 93h			; 93h=2-1-0-3 => xmm2 gets rotated left by one float
+	shufps	xmm3, xmm3, 93h			; 93h=2-1-0-3 => xmm3 gets rotated left by one float
+	shufps	xmm4, xmm4, 93h			; 93h=2-1-0-3 => xmm4 gets rotated left by one float
+	movss	xmm4, xmm3
+	movss	xmm3, xmm2
+	movss	xmm2, xmm0
+
+	; xmm7:xmm6:xmm5 += xmm0:xmm0:xmm0 * xmm4:xmm3:xmm2
+	movaps	xmm1, xmm0
+	mulps	xmm1, xmm2
+	addps	xmm5, xmm1
+	movaps	xmm1, xmm0
+	mulps	xmm1, xmm3
+	addps	xmm6, xmm1
+	mulps	xmm0, xmm4
+	addps	xmm7, xmm0
+
+	dec	edx
+	jnz	.loop_start
+.loop_end:
+	; store autoc
+	mov	edx, [esp + 16]			; edx == autoc
+	movups	[edx], xmm5
+	movups	[edx + 16], xmm6
+	movups	[edx + 32], xmm7
+
+.end:
+	ret
+
+	ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old
+	;[ebp + 20] == autoc[]
+	;[ebp + 16] == lag
+	;[ebp + 12] == data_len
+	;[ebp +  8] == data[]
+	;[esp] == __m128
+	;[esp + 16] == __m128
+
+	push	ebp
+	mov	ebp, esp
+	and	esp, -16 ; stack realign for SSE instructions 'movaps' and 'addps'
+	sub	esp, 32
+
+	;ASSERT(lag > 0)
+	;ASSERT(lag <= 16)
+	;ASSERT(lag <= data_len)
+	;ASSERT(data_len > 0)
+
+	;	for(coeff = 0; coeff < lag; coeff++)
+	;		autoc[coeff] = 0.0;
+	xorps	xmm5, xmm5
+	xorps	xmm6, xmm6
+	movaps	[esp], xmm5
+	movaps	[esp + 16], xmm6
+
+	mov	edx, [ebp + 12]			; edx == data_len
+	mov	eax, [ebp +  8]			; eax == &data[sample] <- &data[0]
+
+	movss	xmm0, [eax]			; xmm0 = 0,0,0,data[0]
+	add	eax, 4
+	movaps	xmm1, xmm0			; xmm1 = 0,0,0,data[0]
+	shufps	xmm0, xmm0, 0			; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+	xorps	xmm2, xmm2			; xmm2 = 0,0,0,0
+	xorps	xmm3, xmm3			; xmm3 = 0,0,0,0
+	xorps	xmm4, xmm4			; xmm4 = 0,0,0,0
+	movaps	xmm7, xmm0
+	mulps	xmm7, xmm1
+	addps	xmm5, xmm7
+	dec	edx
+	jz	.loop_end
+	ALIGN 16
+.loop_start:
+	; start by reading the next sample
+	movss	xmm0, [eax]			; xmm0 = 0,0,0,data[sample]
+	add	eax, 4
+	shufps	xmm0, xmm0, 0			; xmm0 = data[sample],data[sample],data[sample],data[sample]
+
+	; shift xmm4:xmm3:xmm2:xmm1 left by one float
+	shufps	xmm1, xmm1, 93h
+	shufps	xmm2, xmm2, 93h
+	shufps	xmm3, xmm3, 93h
+	shufps	xmm4, xmm4, 93h
+	movss	xmm4, xmm3
+	movss	xmm3, xmm2
+	movss	xmm2, xmm1
+	movss	xmm1, xmm0
+
+	; xmmB:xmmA:xmm6:xmm5 += xmm0:xmm0:xmm0:xmm0 * xmm4:xmm3:xmm2:xmm1
+	movaps	xmm7, xmm0
+	mulps	xmm7, xmm1
+	addps	xmm5, xmm7
+	movaps	xmm7, xmm0
+	mulps	xmm7, xmm2
+	addps	xmm6, xmm7
+	movaps	xmm7, xmm0
+	mulps	xmm7, xmm3
+	mulps	xmm0, xmm4
+	addps	xmm7, [esp]
+	addps	xmm0, [esp + 16]
+	movaps	[esp], xmm7
+	movaps	[esp + 16], xmm0
+
+	dec	edx
+	jnz	.loop_start
+.loop_end:
+	; store autoc
+	mov	edx, [ebp + 20]			; edx == autoc
+	movups	[edx], xmm5
+	movups	[edx + 16], xmm6
+	movaps	xmm5, [esp]
+	movaps	xmm6, [esp + 16]
+	movups	[edx + 32], xmm5
+	movups	[edx + 48], xmm6
+.end:
+	mov	esp, ebp
+	pop	ebp
+	ret
+
+;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[])
+;
+;	for(i = 0; i < data_len; i++) {
+;		sum = 0;
+;		for(j = 0; j < order; j++)
+;			sum += qlp_coeff[j] * data[i-j-1];
+;		residual[i] = data[i] - (sum >> lp_quantization);
+;	}
+;
+	ALIGN	16
+cident FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32
+	;[esp + 40]	residual[]
+	;[esp + 36]	lp_quantization
+	;[esp + 32]	order
+	;[esp + 28]	qlp_coeff[]
+	;[esp + 24]	data_len
+	;[esp + 20]	data[]
+
+	;ASSERT(order > 0)
+
+	push	ebp
+	push	ebx
+	push	esi
+	push	edi
+
+	mov	esi, [esp + 20]			; esi = data[]
+	mov	edi, [esp + 40]			; edi = residual[]
+	mov	eax, [esp + 32]			; eax = order
+	mov	ebx, [esp + 24]			; ebx = data_len
+
+	test	ebx, ebx
+	jz	near .end			; do nothing if data_len == 0
+.begin:
+	cmp	eax, byte 1
+	jg	short .i_1more
+
+	mov	ecx, [esp + 28]
+	mov	edx, [ecx]			; edx = qlp_coeff[0]
+	mov	eax, [esi - 4]			; eax = data[-1]
+	mov	ecx, [esp + 36]			; cl = lp_quantization
+	ALIGN	16
+.i_1_loop_i:
+	imul	eax, edx
+	sar	eax, cl
+	neg	eax
+	add	eax, [esi]
+	mov	[edi], eax
+	mov	eax, [esi]
+	add	edi, byte 4
+	add	esi, byte 4
+	dec	ebx
+	jnz	.i_1_loop_i
+
+	jmp	.end
+
+.i_1more:
+	cmp	eax, byte 32			; for order <= 32 there is a faster routine
+	jbe	short .i_32
+
+	; This version is here just for completeness, since FLAC__MAX_LPC_ORDER == 32
+	ALIGN 16
+.i_32more_loop_i:
+	xor	ebp, ebp
+	mov	ecx, [esp + 32]
+	mov	edx, ecx
+	shl	edx, 2
+	add	edx, [esp + 28]
+	neg	ecx
+	ALIGN	16
+.i_32more_loop_j:
+	sub	edx, byte 4
+	mov	eax, [edx]
+	imul	eax, [esi + 4 * ecx]
+	add	ebp, eax
+	inc	ecx
+	jnz	short .i_32more_loop_j
+
+	mov	ecx, [esp + 36]
+	sar	ebp, cl
+	neg	ebp
+	add	ebp, [esi]
+	mov	[edi], ebp
+	add	esi, byte 4
+	add	edi, byte 4
+
+	dec	ebx
+	jnz	.i_32more_loop_i
+
+	jmp	.end
+
+.mov_eip_to_eax:
+	mov	eax, [esp]
+	ret
+
+.i_32:
+	sub	edi, esi
+	neg	eax
+	lea	edx, [eax + eax * 8 + .jumper_0 - .get_eip0]
+	call	.mov_eip_to_eax
+.get_eip0:
+	add	edx, eax
+	inc	edx
+	mov	eax, [esp + 28]			; eax = qlp_coeff[]
+	xor	ebp, ebp
+	jmp	edx
+
+	mov	ecx, [eax + 124]
+	imul	ecx, [esi - 128]
+	add	ebp, ecx
+	mov	ecx, [eax + 120]
+	imul	ecx, [esi - 124]
+	add	ebp, ecx
+	mov	ecx, [eax + 116]
+	imul	ecx, [esi - 120]
+	add	ebp, ecx
+	mov	ecx, [eax + 112]
+	imul	ecx, [esi - 116]
+	add	ebp, ecx
+	mov	ecx, [eax + 108]
+	imul	ecx, [esi - 112]
+	add	ebp, ecx
+	mov	ecx, [eax + 104]
+	imul	ecx, [esi - 108]
+	add	ebp, ecx
+	mov	ecx, [eax + 100]
+	imul	ecx, [esi - 104]
+	add	ebp, ecx
+	mov	ecx, [eax + 96]
+	imul	ecx, [esi - 100]
+	add	ebp, ecx
+	mov	ecx, [eax + 92]
+	imul	ecx, [esi - 96]
+	add	ebp, ecx
+	mov	ecx, [eax + 88]
+	imul	ecx, [esi - 92]
+	add	ebp, ecx
+	mov	ecx, [eax + 84]
+	imul	ecx, [esi - 88]
+	add	ebp, ecx
+	mov	ecx, [eax + 80]
+	imul	ecx, [esi - 84]
+	add	ebp, ecx
+	mov	ecx, [eax + 76]
+	imul	ecx, [esi - 80]
+	add	ebp, ecx
+	mov	ecx, [eax + 72]
+	imul	ecx, [esi - 76]
+	add	ebp, ecx
+	mov	ecx, [eax + 68]
+	imul	ecx, [esi - 72]
+	add	ebp, ecx
+	mov	ecx, [eax + 64]
+	imul	ecx, [esi - 68]
+	add	ebp, ecx
+	mov	ecx, [eax + 60]
+	imul	ecx, [esi - 64]
+	add	ebp, ecx
+	mov	ecx, [eax + 56]
+	imul	ecx, [esi - 60]
+	add	ebp, ecx
+	mov	ecx, [eax + 52]
+	imul	ecx, [esi - 56]
+	add	ebp, ecx
+	mov	ecx, [eax + 48]
+	imul	ecx, [esi - 52]
+	add	ebp, ecx
+	mov	ecx, [eax + 44]
+	imul	ecx, [esi - 48]
+	add	ebp, ecx
+	mov	ecx, [eax + 40]
+	imul	ecx, [esi - 44]
+	add	ebp, ecx
+	mov	ecx, [eax + 36]
+	imul	ecx, [esi - 40]
+	add	ebp, ecx
+	mov	ecx, [eax + 32]
+	imul	ecx, [esi - 36]
+	add	ebp, ecx
+	mov	ecx, [eax + 28]
+	imul	ecx, [esi - 32]
+	add	ebp, ecx
+	mov	ecx, [eax + 24]
+	imul	ecx, [esi - 28]
+	add	ebp, ecx
+	mov	ecx, [eax + 20]
+	imul	ecx, [esi - 24]
+	add	ebp, ecx
+	mov	ecx, [eax + 16]
+	imul	ecx, [esi - 20]
+	add	ebp, ecx
+	mov	ecx, [eax + 12]
+	imul	ecx, [esi - 16]
+	add	ebp, ecx
+	mov	ecx, [eax + 8]
+	imul	ecx, [esi - 12]
+	add	ebp, ecx
+	mov	ecx, [eax + 4]
+	imul	ecx, [esi - 8]
+	add	ebp, ecx
+	mov	ecx, [eax]			; there is one byte missing
+	imul	ecx, [esi - 4]
+	add	ebp, ecx
+.jumper_0:
+
+	mov	ecx, [esp + 36]
+	sar	ebp, cl
+	neg	ebp
+	add	ebp, [esi]
+	mov	[edi + esi], ebp
+	add	esi, byte 4
+
+	dec	ebx
+	jz	short .end
+	xor	ebp, ebp
+	jmp	edx
+
+.end:
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+
+; WATCHOUT: this routine works on 16 bit data which means bits-per-sample for
+; the channel and qlp_coeffs must be <= 16.  Especially note that this routine
+; cannot be used for side-channel coded 16bps channels since the effective bps
+; is 17.
+	ALIGN	16
+cident FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx
+	;[esp + 40]	residual[]
+	;[esp + 36]	lp_quantization
+	;[esp + 32]	order
+	;[esp + 28]	qlp_coeff[]
+	;[esp + 24]	data_len
+	;[esp + 20]	data[]
+
+	;ASSERT(order > 0)
+
+	push	ebp
+	push	ebx
+	push	esi
+	push	edi
+
+	mov	esi, [esp + 20]			; esi = data[]
+	mov	edi, [esp + 40]			; edi = residual[]
+	mov	eax, [esp + 32]			; eax = order
+	mov	ebx, [esp + 24]			; ebx = data_len
+
+	test	ebx, ebx
+	jz	near .end			; do nothing if data_len == 0
+	dec	ebx
+	test	ebx, ebx
+	jz	near .last_one
+
+	mov	edx, [esp + 28]			; edx = qlp_coeff[]
+	movd	mm6, [esp + 36]			; mm6 = 0:lp_quantization
+	mov	ebp, esp
+
+	and	esp, 0xfffffff8
+
+	xor	ecx, ecx
+.copy_qlp_loop:
+	push	word [edx + 4 * ecx]
+	inc	ecx
+	cmp	ecx, eax
+	jnz	short .copy_qlp_loop
+
+	and	ecx, 0x3
+	test	ecx, ecx
+	je	short .za_end
+	sub	ecx, byte 4
+.za_loop:
+	push	word 0
+	inc	eax
+	inc	ecx
+	jnz	short .za_loop
+.za_end:
+
+	movq	mm5, [esp + 2 * eax - 8]
+	movd	mm4, [esi - 16]
+	punpckldq	mm4, [esi - 12]
+	movd	mm0, [esi - 8]
+	punpckldq	mm0, [esi - 4]
+	packssdw	mm4, mm0
+
+	cmp	eax, byte 4
+	jnbe	short .mmx_4more
+
+	ALIGN	16
+.mmx_4_loop_i:
+	movd	mm1, [esi]
+	movq	mm3, mm4
+	punpckldq	mm1, [esi + 4]
+	psrlq	mm4, 16
+	movq	mm0, mm1
+	psllq	mm0, 48
+	por	mm4, mm0
+	movq	mm2, mm4
+	psrlq	mm4, 16
+	pxor	mm0, mm0
+	punpckhdq	mm0, mm1
+	pmaddwd	mm3, mm5
+	pmaddwd	mm2, mm5
+	psllq	mm0, 16
+	por	mm4, mm0
+	movq	mm0, mm3
+	punpckldq	mm3, mm2
+	punpckhdq	mm0, mm2
+	paddd	mm3, mm0
+	psrad	mm3, mm6
+	psubd	mm1, mm3
+	movd	[edi], mm1
+	punpckhdq	mm1, mm1
+	movd	[edi + 4], mm1
+
+	add	edi, byte 8
+	add	esi, byte 8
+
+	sub	ebx, 2
+	jg	.mmx_4_loop_i
+	jmp	.mmx_end
+
+.mmx_4more:
+	shl	eax, 2
+	neg	eax
+	add	eax, byte 16
+
+	ALIGN	16
+.mmx_4more_loop_i:
+	movd	mm1, [esi]
+	punpckldq	mm1, [esi + 4]
+	movq	mm3, mm4
+	psrlq	mm4, 16
+	movq	mm0, mm1
+	psllq	mm0, 48
+	por	mm4, mm0
+	movq	mm2, mm4
+	psrlq	mm4, 16
+	pxor	mm0, mm0
+	punpckhdq	mm0, mm1
+	pmaddwd	mm3, mm5
+	pmaddwd	mm2, mm5
+	psllq	mm0, 16
+	por	mm4, mm0
+
+	mov	ecx, esi
+	add	ecx, eax
+	mov	edx, esp
+
+	ALIGN	16
+.mmx_4more_loop_j:
+	movd	mm0, [ecx - 16]
+	movd	mm7, [ecx - 8]
+	punpckldq	mm0, [ecx - 12]
+	punpckldq	mm7, [ecx - 4]
+	packssdw	mm0, mm7
+	pmaddwd	mm0, [edx]
+	punpckhdq	mm7, mm7
+	paddd	mm3, mm0
+	movd	mm0, [ecx - 12]
+	punpckldq	mm0, [ecx - 8]
+	punpckldq	mm7, [ecx]
+	packssdw	mm0, mm7
+	pmaddwd	mm0, [edx]
+	paddd	mm2, mm0
+
+	add	edx, byte 8
+	add	ecx, byte 16
+	cmp	ecx, esi
+	jnz	.mmx_4more_loop_j
+
+	movq	mm0, mm3
+	punpckldq	mm3, mm2
+	punpckhdq	mm0, mm2
+	paddd	mm3, mm0
+	psrad	mm3, mm6
+	psubd	mm1, mm3
+	movd	[edi], mm1
+	punpckhdq	mm1, mm1
+	movd	[edi + 4], mm1
+
+	add	edi, byte 8
+	add	esi, byte 8
+
+	sub	ebx, 2
+	jg	near .mmx_4more_loop_i
+
+.mmx_end:
+	emms
+	mov	esp, ebp
+.last_one:
+	mov	eax, [esp + 32]
+	inc	ebx
+	jnz	near FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32.begin
+
+.end:
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+
+; **********************************************************************
+;
+; 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[])
+; {
+; 	unsigned i, j;
+; 	FLAC__int32 sum;
+;
+; 	FLAC__ASSERT(order > 0);
+;
+; 	for(i = 0; i < data_len; i++) {
+; 		sum = 0;
+; 		for(j = 0; j < order; j++)
+; 			sum += qlp_coeff[j] * data[i-j-1];
+; 		data[i] = residual[i] + (sum >> lp_quantization);
+; 	}
+; }
+	ALIGN	16
+cident FLAC__lpc_restore_signal_asm_ia32
+	;[esp + 40]	data[]
+	;[esp + 36]	lp_quantization
+	;[esp + 32]	order
+	;[esp + 28]	qlp_coeff[]
+	;[esp + 24]	data_len
+	;[esp + 20]	residual[]
+
+	;ASSERT(order > 0)
+
+	push	ebp
+	push	ebx
+	push	esi
+	push	edi
+
+	mov	esi, [esp + 20]			; esi = residual[]
+	mov	edi, [esp + 40]			; edi = data[]
+	mov	eax, [esp + 32]			; eax = order
+	mov	ebx, [esp + 24]			; ebx = data_len
+
+	test	ebx, ebx
+	jz	near .end			; do nothing if data_len == 0
+
+.begin:
+	cmp	eax, byte 1
+	jg	short .x87_1more
+
+	mov	ecx, [esp + 28]
+	mov	edx, [ecx]
+	mov	eax, [edi - 4]
+	mov	ecx, [esp + 36]
+	ALIGN	16
+.x87_1_loop_i:
+	imul	eax, edx
+	sar	eax, cl
+	add	eax, [esi]
+	mov	[edi], eax
+	add	esi, byte 4
+	add	edi, byte 4
+	dec	ebx
+	jnz	.x87_1_loop_i
+
+	jmp	.end
+
+.x87_1more:
+	cmp	eax, byte 32			; for order <= 32 there is a faster routine
+	jbe	short .x87_32
+
+	; This version is here just for completeness, since FLAC__MAX_LPC_ORDER == 32
+	ALIGN 16
+.x87_32more_loop_i:
+	xor	ebp, ebp
+	mov	ecx, [esp + 32]
+	mov	edx, ecx
+	shl	edx, 2
+	add	edx, [esp + 28]
+	neg	ecx
+	ALIGN	16
+.x87_32more_loop_j:
+	sub	edx, byte 4
+	mov	eax, [edx]
+	imul	eax, [edi + 4 * ecx]
+	add	ebp, eax
+	inc	ecx
+	jnz	short .x87_32more_loop_j
+
+	mov	ecx, [esp + 36]
+	sar	ebp, cl
+	add	ebp, [esi]
+	mov	[edi], ebp
+	add	edi, byte 4
+	add	esi, byte 4
+
+	dec	ebx
+	jnz	.x87_32more_loop_i
+
+	jmp	.end
+
+.mov_eip_to_eax:
+	mov	eax, [esp]
+	ret
+
+.x87_32:
+	sub	esi, edi
+	neg	eax
+	lea	edx, [eax + eax * 8 + .jumper_0 - .get_eip0]
+	call	.mov_eip_to_eax
+.get_eip0:
+	add	edx, eax
+	inc	edx				; compensate for the shorter opcode on the last iteration
+	mov	eax, [esp + 28]			; eax = qlp_coeff[]
+	xor	ebp, ebp
+	jmp	edx
+
+	mov	ecx, [eax + 124]		; ecx =  qlp_coeff[31]
+	imul	ecx, [edi - 128]		; ecx =  qlp_coeff[31] * data[i-32]
+	add	ebp, ecx			; sum += qlp_coeff[31] * data[i-32]
+	mov	ecx, [eax + 120]		; ecx =  qlp_coeff[30]
+	imul	ecx, [edi - 124]		; ecx =  qlp_coeff[30] * data[i-31]
+	add	ebp, ecx			; sum += qlp_coeff[30] * data[i-31]
+	mov	ecx, [eax + 116]		; ecx =  qlp_coeff[29]
+	imul	ecx, [edi - 120]		; ecx =  qlp_coeff[29] * data[i-30]
+	add	ebp, ecx			; sum += qlp_coeff[29] * data[i-30]
+	mov	ecx, [eax + 112]		; ecx =  qlp_coeff[28]
+	imul	ecx, [edi - 116]		; ecx =  qlp_coeff[28] * data[i-29]
+	add	ebp, ecx			; sum += qlp_coeff[28] * data[i-29]
+	mov	ecx, [eax + 108]		; ecx =  qlp_coeff[27]
+	imul	ecx, [edi - 112]		; ecx =  qlp_coeff[27] * data[i-28]
+	add	ebp, ecx			; sum += qlp_coeff[27] * data[i-28]
+	mov	ecx, [eax + 104]		; ecx =  qlp_coeff[26]
+	imul	ecx, [edi - 108]		; ecx =  qlp_coeff[26] * data[i-27]
+	add	ebp, ecx			; sum += qlp_coeff[26] * data[i-27]
+	mov	ecx, [eax + 100]		; ecx =  qlp_coeff[25]
+	imul	ecx, [edi - 104]		; ecx =  qlp_coeff[25] * data[i-26]
+	add	ebp, ecx			; sum += qlp_coeff[25] * data[i-26]
+	mov	ecx, [eax + 96]			; ecx =  qlp_coeff[24]
+	imul	ecx, [edi - 100]		; ecx =  qlp_coeff[24] * data[i-25]
+	add	ebp, ecx			; sum += qlp_coeff[24] * data[i-25]
+	mov	ecx, [eax + 92]			; ecx =  qlp_coeff[23]
+	imul	ecx, [edi - 96]			; ecx =  qlp_coeff[23] * data[i-24]
+	add	ebp, ecx			; sum += qlp_coeff[23] * data[i-24]
+	mov	ecx, [eax + 88]			; ecx =  qlp_coeff[22]
+	imul	ecx, [edi - 92]			; ecx =  qlp_coeff[22] * data[i-23]
+	add	ebp, ecx			; sum += qlp_coeff[22] * data[i-23]
+	mov	ecx, [eax + 84]			; ecx =  qlp_coeff[21]
+	imul	ecx, [edi - 88]			; ecx =  qlp_coeff[21] * data[i-22]
+	add	ebp, ecx			; sum += qlp_coeff[21] * data[i-22]
+	mov	ecx, [eax + 80]			; ecx =  qlp_coeff[20]
+	imul	ecx, [edi - 84]			; ecx =  qlp_coeff[20] * data[i-21]
+	add	ebp, ecx			; sum += qlp_coeff[20] * data[i-21]
+	mov	ecx, [eax + 76]			; ecx =  qlp_coeff[19]
+	imul	ecx, [edi - 80]			; ecx =  qlp_coeff[19] * data[i-20]
+	add	ebp, ecx			; sum += qlp_coeff[19] * data[i-20]
+	mov	ecx, [eax + 72]			; ecx =  qlp_coeff[18]
+	imul	ecx, [edi - 76]			; ecx =  qlp_coeff[18] * data[i-19]
+	add	ebp, ecx			; sum += qlp_coeff[18] * data[i-19]
+	mov	ecx, [eax + 68]			; ecx =  qlp_coeff[17]
+	imul	ecx, [edi - 72]			; ecx =  qlp_coeff[17] * data[i-18]
+	add	ebp, ecx			; sum += qlp_coeff[17] * data[i-18]
+	mov	ecx, [eax + 64]			; ecx =  qlp_coeff[16]
+	imul	ecx, [edi - 68]			; ecx =  qlp_coeff[16] * data[i-17]
+	add	ebp, ecx			; sum += qlp_coeff[16] * data[i-17]
+	mov	ecx, [eax + 60]			; ecx =  qlp_coeff[15]
+	imul	ecx, [edi - 64]			; ecx =  qlp_coeff[15] * data[i-16]
+	add	ebp, ecx			; sum += qlp_coeff[15] * data[i-16]
+	mov	ecx, [eax + 56]			; ecx =  qlp_coeff[14]
+	imul	ecx, [edi - 60]			; ecx =  qlp_coeff[14] * data[i-15]
+	add	ebp, ecx			; sum += qlp_coeff[14] * data[i-15]
+	mov	ecx, [eax + 52]			; ecx =  qlp_coeff[13]
+	imul	ecx, [edi - 56]			; ecx =  qlp_coeff[13] * data[i-14]
+	add	ebp, ecx			; sum += qlp_coeff[13] * data[i-14]
+	mov	ecx, [eax + 48]			; ecx =  qlp_coeff[12]
+	imul	ecx, [edi - 52]			; ecx =  qlp_coeff[12] * data[i-13]
+	add	ebp, ecx			; sum += qlp_coeff[12] * data[i-13]
+	mov	ecx, [eax + 44]			; ecx =  qlp_coeff[11]
+	imul	ecx, [edi - 48]			; ecx =  qlp_coeff[11] * data[i-12]
+	add	ebp, ecx			; sum += qlp_coeff[11] * data[i-12]
+	mov	ecx, [eax + 40]			; ecx =  qlp_coeff[10]
+	imul	ecx, [edi - 44]			; ecx =  qlp_coeff[10] * data[i-11]
+	add	ebp, ecx			; sum += qlp_coeff[10] * data[i-11]
+	mov	ecx, [eax + 36]			; ecx =  qlp_coeff[ 9]
+	imul	ecx, [edi - 40]			; ecx =  qlp_coeff[ 9] * data[i-10]
+	add	ebp, ecx			; sum += qlp_coeff[ 9] * data[i-10]
+	mov	ecx, [eax + 32]			; ecx =  qlp_coeff[ 8]
+	imul	ecx, [edi - 36]			; ecx =  qlp_coeff[ 8] * data[i- 9]
+	add	ebp, ecx			; sum += qlp_coeff[ 8] * data[i- 9]
+	mov	ecx, [eax + 28]			; ecx =  qlp_coeff[ 7]
+	imul	ecx, [edi - 32]			; ecx =  qlp_coeff[ 7] * data[i- 8]
+	add	ebp, ecx			; sum += qlp_coeff[ 7] * data[i- 8]
+	mov	ecx, [eax + 24]			; ecx =  qlp_coeff[ 6]
+	imul	ecx, [edi - 28]			; ecx =  qlp_coeff[ 6] * data[i- 7]
+	add	ebp, ecx			; sum += qlp_coeff[ 6] * data[i- 7]
+	mov	ecx, [eax + 20]			; ecx =  qlp_coeff[ 5]
+	imul	ecx, [edi - 24]			; ecx =  qlp_coeff[ 5] * data[i- 6]
+	add	ebp, ecx			; sum += qlp_coeff[ 5] * data[i- 6]
+	mov	ecx, [eax + 16]			; ecx =  qlp_coeff[ 4]
+	imul	ecx, [edi - 20]			; ecx =  qlp_coeff[ 4] * data[i- 5]
+	add	ebp, ecx			; sum += qlp_coeff[ 4] * data[i- 5]
+	mov	ecx, [eax + 12]			; ecx =  qlp_coeff[ 3]
+	imul	ecx, [edi - 16]			; ecx =  qlp_coeff[ 3] * data[i- 4]
+	add	ebp, ecx			; sum += qlp_coeff[ 3] * data[i- 4]
+	mov	ecx, [eax + 8]			; ecx =  qlp_coeff[ 2]
+	imul	ecx, [edi - 12]			; ecx =  qlp_coeff[ 2] * data[i- 3]
+	add	ebp, ecx			; sum += qlp_coeff[ 2] * data[i- 3]
+	mov	ecx, [eax + 4]			; ecx =  qlp_coeff[ 1]
+	imul	ecx, [edi - 8]			; ecx =  qlp_coeff[ 1] * data[i- 2]
+	add	ebp, ecx			; sum += qlp_coeff[ 1] * data[i- 2]
+	mov	ecx, [eax]			; ecx =  qlp_coeff[ 0] (NOTE: one byte missing from instruction)
+	imul	ecx, [edi - 4]			; ecx =  qlp_coeff[ 0] * data[i- 1]
+	add	ebp, ecx			; sum += qlp_coeff[ 0] * data[i- 1]
+.jumper_0:
+
+	mov	ecx, [esp + 36]
+	sar	ebp, cl				; ebp = (sum >> lp_quantization)
+	add	ebp, [esi + edi]		; ebp = residual[i] + (sum >> lp_quantization)
+	mov	[edi], ebp			; data[i] = residual[i] + (sum >> lp_quantization)
+	add	edi, byte 4
+
+	dec	ebx
+	jz	short .end
+	xor	ebp, ebp
+	jmp	edx
+
+.end:
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+
+; WATCHOUT: this routine works on 16 bit data which means bits-per-sample for
+; the channel and qlp_coeffs must be <= 16.  Especially note that this routine
+; cannot be used for side-channel coded 16bps channels since the effective bps
+; is 17.
+; WATCHOUT: this routine requires that each data array have a buffer of up to
+; 3 zeroes in front (at negative indices) for alignment purposes, i.e. for each
+; channel n, data[n][-1] through data[n][-3] should be accessible and zero.
+	ALIGN	16
+cident FLAC__lpc_restore_signal_asm_ia32_mmx
+	;[esp + 40]	data[]
+	;[esp + 36]	lp_quantization
+	;[esp + 32]	order
+	;[esp + 28]	qlp_coeff[]
+	;[esp + 24]	data_len
+	;[esp + 20]	residual[]
+
+	;ASSERT(order > 0)
+
+	push	ebp
+	push	ebx
+	push	esi
+	push	edi
+
+	mov	esi, [esp + 20]
+	mov	edi, [esp + 40]
+	mov	eax, [esp + 32]
+	mov	ebx, [esp + 24]
+
+	test	ebx, ebx
+	jz	near .end			; do nothing if data_len == 0
+	cmp	eax, byte 4
+	jb	near FLAC__lpc_restore_signal_asm_ia32.begin
+
+	mov	edx, [esp + 28]
+	movd	mm6, [esp + 36]
+	mov	ebp, esp
+
+	and	esp, 0xfffffff8
+
+	xor	ecx, ecx
+.copy_qlp_loop:
+	push	word [edx + 4 * ecx]
+	inc	ecx
+	cmp	ecx, eax
+	jnz	short .copy_qlp_loop
+
+	and	ecx, 0x3
+	test	ecx, ecx
+	je	short .za_end
+	sub	ecx, byte 4
+.za_loop:
+	push	word 0
+	inc	eax
+	inc	ecx
+	jnz	short .za_loop
+.za_end:
+
+	movq	mm5, [esp + 2 * eax - 8]
+	movd	mm4, [edi - 16]
+	punpckldq	mm4, [edi - 12]
+	movd	mm0, [edi - 8]
+	punpckldq	mm0, [edi - 4]
+	packssdw	mm4, mm0
+
+	cmp	eax, byte 4
+	jnbe	short .mmx_4more
+
+	ALIGN	16
+.mmx_4_loop_i:
+	movq	mm7, mm4
+	pmaddwd	mm7, mm5
+	movq	mm0, mm7
+	punpckhdq	mm7, mm7
+	paddd	mm7, mm0
+	psrad	mm7, mm6
+	movd	mm1, [esi]
+	paddd	mm7, mm1
+	movd	[edi], mm7
+	psllq	mm7, 48
+	psrlq	mm4, 16
+	por	mm4, mm7
+
+	add	esi, byte 4
+	add	edi, byte 4
+
+	dec	ebx
+	jnz	.mmx_4_loop_i
+	jmp	.mmx_end
+.mmx_4more:
+	shl	eax, 2
+	neg	eax
+	add	eax, byte 16
+	ALIGN	16
+.mmx_4more_loop_i:
+	mov	ecx, edi
+	add	ecx, eax
+	mov	edx, esp
+
+	movq	mm7, mm4
+	pmaddwd	mm7, mm5
+
+	ALIGN	16
+.mmx_4more_loop_j:
+	movd	mm0, [ecx - 16]
+	punpckldq	mm0, [ecx - 12]
+	movd	mm1, [ecx - 8]
+	punpckldq	mm1, [ecx - 4]
+	packssdw	mm0, mm1
+	pmaddwd	mm0, [edx]
+	paddd	mm7, mm0
+
+	add	edx, byte 8
+	add	ecx, byte 16
+	cmp	ecx, edi
+	jnz	.mmx_4more_loop_j
+
+	movq	mm0, mm7
+	punpckhdq	mm7, mm7
+	paddd	mm7, mm0
+	psrad	mm7, mm6
+	movd	mm1, [esi]
+	paddd	mm7, mm1
+	movd	[edi], mm7
+	psllq	mm7, 48
+	psrlq	mm4, 16
+	por	mm4, mm7
+
+	add	esi, byte 4
+	add	edi, byte 4
+
+	dec	ebx
+	jnz	short .mmx_4more_loop_i
+.mmx_end:
+	emms
+	mov	esp, ebp
+
+.end:
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+
+
+; **********************************************************************
+;
+;void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+; {
+; 	unsigned i, j;
+; 	FLAC__int64 sum;
+;
+; 	FLAC__ASSERT(order > 0);
+;
+;	for(i = 0; i < data_len; i++) {
+;		sum = 0;
+;		for(j = 0; j < order; j++)
+;			sum += qlp_coeff[j] * (FLAC__int64)data[i-j-1];
+;		residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+;	}
+; }
+	ALIGN	16
+cident FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32
+	;[esp + 40]	residual[]
+	;[esp + 36]	lp_quantization
+	;[esp + 32]	order
+	;[esp + 28]	qlp_coeff[]
+	;[esp + 24]	data_len
+	;[esp + 20]	data[]
+
+	;ASSERT(order > 0)
+	;ASSERT(order <= 32)
+	;ASSERT(lp_quantization <= 31)
+
+	push	ebp
+	push	ebx
+	push	esi
+	push	edi
+
+	mov	ebx, [esp + 24]			; ebx = data_len
+	test	ebx, ebx
+	jz	near .end			; do nothing if data_len == 0
+
+.begin:
+	mov	eax, [esp + 32]			; eax = order
+	cmp	eax, 1
+	jg	short .i_32
+
+	mov	esi, [esp + 40]			; esi = residual[]
+	mov	edi, [esp + 20]			; edi = data[]
+	mov	ecx, [esp + 28]			; ecx = qlp_coeff[]
+	mov	ebp, [ecx]			; ebp = qlp_coeff[0]
+	mov	eax, [edi - 4]			; eax = data[-1]
+	mov	ecx, [esp + 36]			; cl = lp_quantization
+	ALIGN	16
+.i_1_loop_i:
+	imul	ebp				; edx:eax = qlp_coeff[0] * (FLAC__int64)data[i-1]
+	shrd	eax, edx, cl			; 0 <= lp_quantization <= 15
+	neg	eax
+	add	eax, [edi]
+	mov	[esi], eax
+	mov	eax, [edi]
+	add	esi, 4
+	add	edi, 4
+	dec	ebx
+	jnz	.i_1_loop_i
+	jmp	.end
+
+.mov_eip_to_eax:
+	mov	eax, [esp]
+	ret
+
+.i_32:	; eax = order
+	neg	eax
+	add	eax, eax
+	lea	ebp, [eax + eax * 4 + .jumper_0 - .get_eip0]
+	call	.mov_eip_to_eax
+.get_eip0:
+	add	ebp, eax
+	inc	ebp				; compensate for the shorter opcode on the last iteration
+
+	mov	ebx, [esp + 28]			; ebx = qlp_coeff[]
+	mov	edi, [esp + 20]			; edi = data[]
+	sub	[esp + 40], edi			; residual[] -= data[]
+
+	xor	ecx, ecx
+	xor	esi, esi
+	jmp	ebp
+
+;eax = --
+;edx = --
+;ecx = 0
+;esi = 0
+;
+;ebx = qlp_coeff[]
+;edi = data[]
+;ebp = @address
+
+	mov	eax, [ebx + 124]		; eax =  qlp_coeff[31]
+	imul	dword [edi - 128]		; edx:eax =  qlp_coeff[31] * data[i-32]
+	add	ecx, eax
+	adc	esi, edx			; sum += qlp_coeff[31] * data[i-32]
+
+	mov	eax, [ebx + 120]		; eax =  qlp_coeff[30]
+	imul	dword [edi - 124]		; edx:eax =  qlp_coeff[30] * data[i-31]
+	add	ecx, eax
+	adc	esi, edx			; sum += qlp_coeff[30] * data[i-31]
+
+	mov	eax, [ebx + 116]
+	imul	dword [edi - 120]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 112]
+	imul	dword [edi - 116]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 108]
+	imul	dword [edi - 112]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 104]
+	imul	dword [edi - 108]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 100]
+	imul	dword [edi - 104]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 96]
+	imul	dword [edi - 100]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 92]
+	imul	dword [edi - 96]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 88]
+	imul	dword [edi - 92]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 84]
+	imul	dword [edi - 88]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 80]
+	imul	dword [edi - 84]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 76]
+	imul	dword [edi - 80]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 72]
+	imul	dword [edi - 76]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 68]
+	imul	dword [edi - 72]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 64]
+	imul	dword [edi - 68]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 60]
+	imul	dword [edi - 64]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 56]
+	imul	dword [edi - 60]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 52]
+	imul	dword [edi - 56]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 48]
+	imul	dword [edi - 52]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 44]
+	imul	dword [edi - 48]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 40]
+	imul	dword [edi - 44]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 36]
+	imul	dword [edi - 40]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 32]
+	imul	dword [edi - 36]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 28]
+	imul	dword [edi - 32]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 24]
+	imul	dword [edi - 28]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 20]
+	imul	dword [edi - 24]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 16]
+	imul	dword [edi - 20]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 12]
+	imul	dword [edi - 16]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 8]
+	imul	dword [edi - 12]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 4]
+	imul	dword [edi - 8]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx]			; eax =  qlp_coeff[ 0] (NOTE: one byte missing from instruction)
+	imul	dword [edi - 4]			; edx:eax =  qlp_coeff[ 0] * data[i- 1]
+	add	ecx, eax
+	adc	esi, edx			; sum += qlp_coeff[ 0] * data[i- 1]
+
+.jumper_0:
+	mov	edx, ecx
+;esi:edx = sum
+	mov	ecx, [esp + 36]			; cl = lp_quantization
+	shrd	edx, esi, cl			; edx = (sum >> lp_quantization)
+;eax = --
+;ecx = --
+;edx = sum >> lp_q
+;esi = --
+	neg	edx				; edx = -(sum >> lp_quantization)
+	mov	eax, [esp + 40]			; residual[] - data[]
+	add	edx, [edi]			; edx = data[i] - (sum >> lp_quantization)
+	mov	[edi + eax], edx
+	add	edi, 4
+
+	dec	dword [esp + 24]
+	jz	short .end
+	xor	ecx, ecx
+	xor	esi, esi
+	jmp	ebp
+
+.end:
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+
+; **********************************************************************
+;
+; void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+; {
+; 	unsigned i, j;
+; 	FLAC__int64 sum;
+;
+; 	FLAC__ASSERT(order > 0);
+;
+; 	for(i = 0; i < data_len; i++) {
+; 		sum = 0;
+; 		for(j = 0; j < order; j++)
+; 			sum += qlp_coeff[j] * (FLAC__int64)data[i-j-1];
+; 		data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+; 	}
+; }
+	ALIGN	16
+cident FLAC__lpc_restore_signal_wide_asm_ia32
+	;[esp + 40]	data[]
+	;[esp + 36]	lp_quantization
+	;[esp + 32]	order
+	;[esp + 28]	qlp_coeff[]
+	;[esp + 24]	data_len
+	;[esp + 20]	residual[]
+
+	;ASSERT(order > 0)
+	;ASSERT(order <= 32)
+	;ASSERT(lp_quantization <= 31)
+
+	push	ebp
+	push	ebx
+	push	esi
+	push	edi
+
+	mov	ebx, [esp + 24]			; ebx = data_len
+	test	ebx, ebx
+	jz	near .end			; do nothing if data_len == 0
+
+.begin:
+	mov	eax, [esp + 32]			; eax = order
+	cmp	eax, 1
+	jg	short .x87_32
+
+	mov	esi, [esp + 20]			; esi = residual[]
+	mov	edi, [esp + 40]			; edi = data[]
+	mov	ecx, [esp + 28]			; ecx = qlp_coeff[]
+	mov	ebp, [ecx]			; ebp = qlp_coeff[0]
+	mov	eax, [edi - 4]			; eax = data[-1]
+	mov	ecx, [esp + 36]			; cl = lp_quantization
+	ALIGN	16
+.x87_1_loop_i:
+	imul	ebp				; edx:eax = qlp_coeff[0] * (FLAC__int64)data[i-1]
+	shrd	eax, edx, cl			; 0 <= lp_quantization <= 15
+;
+	add	eax, [esi]
+	mov	[edi], eax
+;
+	add	esi, 4
+	add	edi, 4
+	dec	ebx
+	jnz	.x87_1_loop_i
+	jmp	.end
+
+.mov_eip_to_eax:
+	mov	eax, [esp]
+	ret
+
+.x87_32:	; eax = order
+	neg	eax
+	add	eax, eax
+	lea	ebp, [eax + eax * 4 + .jumper_0 - .get_eip0]
+	call	.mov_eip_to_eax
+.get_eip0:
+	add	ebp, eax
+	inc	ebp				; compensate for the shorter opcode on the last iteration
+
+	mov	ebx, [esp + 28]			; ebx = qlp_coeff[]
+	mov	edi, [esp + 40]			; esi = data[]
+	sub	[esp + 20], edi			; residual[] -= data[]
+
+	xor	ecx, ecx
+	xor	esi, esi
+	jmp	ebp
+
+;eax = --
+;edx = --
+;ecx = 0
+;esi = 0
+;
+;ebx = qlp_coeff[]
+;edi = data[]
+;ebp = @address
+
+	mov	eax, [ebx + 124]		; eax =  qlp_coeff[31]
+	imul	dword [edi - 128]		; edx:eax =  qlp_coeff[31] * data[i-32]
+	add	ecx, eax
+	adc	esi, edx			; sum += qlp_coeff[31] * data[i-32]
+
+	mov	eax, [ebx + 120]		; eax =  qlp_coeff[30]
+	imul	dword [edi - 124]		; edx:eax =  qlp_coeff[30] * data[i-31]
+	add	ecx, eax
+	adc	esi, edx			; sum += qlp_coeff[30] * data[i-31]
+
+	mov	eax, [ebx + 116]
+	imul	dword [edi - 120]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 112]
+	imul	dword [edi - 116]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 108]
+	imul	dword [edi - 112]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 104]
+	imul	dword [edi - 108]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 100]
+	imul	dword [edi - 104]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 96]
+	imul	dword [edi - 100]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 92]
+	imul	dword [edi - 96]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 88]
+	imul	dword [edi - 92]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 84]
+	imul	dword [edi - 88]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 80]
+	imul	dword [edi - 84]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 76]
+	imul	dword [edi - 80]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 72]
+	imul	dword [edi - 76]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 68]
+	imul	dword [edi - 72]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 64]
+	imul	dword [edi - 68]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 60]
+	imul	dword [edi - 64]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 56]
+	imul	dword [edi - 60]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 52]
+	imul	dword [edi - 56]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 48]
+	imul	dword [edi - 52]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 44]
+	imul	dword [edi - 48]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 40]
+	imul	dword [edi - 44]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 36]
+	imul	dword [edi - 40]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 32]
+	imul	dword [edi - 36]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 28]
+	imul	dword [edi - 32]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 24]
+	imul	dword [edi - 28]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 20]
+	imul	dword [edi - 24]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 16]
+	imul	dword [edi - 20]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 12]
+	imul	dword [edi - 16]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 8]
+	imul	dword [edi - 12]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx + 4]
+	imul	dword [edi - 8]
+	add	ecx, eax
+	adc	esi, edx
+
+	mov	eax, [ebx]			; eax =  qlp_coeff[ 0] (NOTE: one byte missing from instruction)
+	imul	dword [edi - 4]			; edx:eax =  qlp_coeff[ 0] * data[i- 1]
+	add	ecx, eax
+	adc	esi, edx			; sum += qlp_coeff[ 0] * data[i- 1]
+
+.jumper_0:
+	mov	edx, ecx
+;esi:edx = sum
+	mov	ecx, [esp + 36]			; cl = lp_quantization
+	shrd	edx, esi, cl			; edx = (sum >> lp_quantization)
+;eax = --
+;ecx = --
+;edx = sum >> lp_q
+;esi = --
+;
+	mov	eax, [esp + 20]			; residual[] - data[]
+	add	edx, [edi + eax]		; edx = residual[i] + (sum >> lp_quantization)
+	mov	[edi], edx			; data[i] = residual[i] + (sum >> lp_quantization)
+	add	edi, 4
+
+	dec	dword [esp + 24]
+	jz	short .end
+	xor	ecx, ecx
+	xor	esi, esi
+	jmp	ebp
+
+.end:
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+
+; end
diff --git a/src/libFLAC/ia32/nasm.h b/src/libFLAC/ia32/nasm.h
new file mode 100644
index 0000000..7850cd2
--- /dev/null
+++ b/src/libFLAC/ia32/nasm.h
@@ -0,0 +1,95 @@
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001-2009  Josh Coalson
+;  Copyright (C) 2011-2016  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.
+
+	bits 32
+
+%ifdef OBJ_FORMAT_win32
+	%define FLAC__PUBLIC_NEEDS_UNDERSCORE
+	%idefine code_section section .text align=16 class=CODE use32
+	%idefine data_section section .data align=32 class=DATA use32
+	%idefine bss_section  section .bss  align=32 class=DATA use32
+%elifdef OBJ_FORMAT_aout
+	%define FLAC__PUBLIC_NEEDS_UNDERSCORE
+	%idefine code_section section .text
+	%idefine data_section section .data
+	%idefine bss_section  section .bss
+%elifdef OBJ_FORMAT_aoutb
+	%define FLAC__PUBLIC_NEEDS_UNDERSCORE
+	%idefine code_section section .text
+	%idefine data_section section .data
+	%idefine bss_section  section .bss
+%elifdef OBJ_FORMAT_coff
+	%define FLAC__PUBLIC_NEEDS_UNDERSCORE
+	%idefine code_section section .text
+	%idefine data_section section .data
+	%idefine bss_section  section .bss
+%elifdef OBJ_FORMAT_macho
+	%define FLAC__PUBLIC_NEEDS_UNDERSCORE
+	%idefine code_section section .text
+	%idefine data_section section .data
+	%idefine bss_section  section .bss
+%elifdef OBJ_FORMAT_elf
+	%idefine code_section section .text align=16
+	%idefine data_section section .data align=32
+	%idefine bss_section  section .bss  align=32
+%else
+	%error unsupported object format! ; this directive doesn't really work here
+%endif
+
+%imacro cglobal 1
+	%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+		global _%1
+	%else
+		%if __NASM_MAJOR__ >= 2
+			global %1:function hidden
+		%else
+			global %1
+		%endif
+	%endif
+%endmacro
+
+%imacro cextern 1
+	%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+		extern _%1
+	%else
+		extern %1
+	%endif
+%endmacro
+
+%imacro cident 1
+_%1:
+%1:
+%endmacro
+
+%ifdef OBJ_FORMAT_elf
+section .note.GNU-stack progbits noalloc noexec nowrite align=1
+%endif
+
diff --git a/src/libFLAC/include/Makefile.am b/src/libFLAC/include/Makefile.am
new file mode 100644
index 0000000..99e98a4
--- /dev/null
+++ b/src/libFLAC/include/Makefile.am
@@ -0,0 +1,32 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+SUBDIRS = private protected
diff --git a/src/libFLAC/include/private/Makefile.am b/src/libFLAC/include/private/Makefile.am
new file mode 100644
index 0000000..49bcda7
--- /dev/null
+++ b/src/libFLAC/include/private/Makefile.am
@@ -0,0 +1,53 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+noinst_HEADERS = \
+	all.h \
+	bitmath.h \
+	bitreader.h \
+	bitwriter.h \
+	cpu.h \
+	crc.h \
+	fixed.h \
+	float.h \
+	format.h \
+	lpc.h \
+	macros.h \
+	md5.h \
+	memory.h \
+	metadata.h \
+	ogg_decoder_aspect.h \
+	ogg_encoder_aspect.h \
+	ogg_helper.h \
+	ogg_mapping.h \
+	stream_encoder.h \
+	stream_encoder_framing.h \
+	window.h
diff --git a/libFLAC/include/private/all.h b/src/libFLAC/include/private/all.h
similarity index 100%
rename from libFLAC/include/private/all.h
rename to src/libFLAC/include/private/all.h
diff --git a/src/libFLAC/include/private/bitmath.h b/src/libFLAC/include/private/bitmath.h
new file mode 100644
index 0000000..12a3fb9
--- /dev/null
+++ b/src/libFLAC/include/private/bitmath.h
@@ -0,0 +1,210 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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__BITMATH_H
+#define FLAC__PRIVATE__BITMATH_H
+
+#include "FLAC/ordinals.h"
+#include "FLAC/assert.h"
+
+#include "share/compat.h"
+
+#if defined(_MSC_VER)
+#include <intrin.h> /* for _BitScanReverse* */
+#endif
+
+/* Will never be emitted for MSVC, GCC, Intel compilers */
+static inline uint32_t FLAC__clz_soft_uint32(FLAC__uint32 word)
+{
+	static const uint8_t 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 uint32_t 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)
+	{
+		uint32_t idx;
+		_BitScanReverse(&idx, v);
+		return idx ^ 31U;
+	}
+#else
+	return FLAC__clz_soft_uint32(v);
+#endif
+}
+
+/* Used when 64-bit bsr/clz is unavailable; can use 32-bit bsr/clz when possible */
+static inline uint32_t FLAC__clz_soft_uint64(FLAC__uint64 word)
+{
+	return (FLAC__uint32)(word>>32) ? FLAC__clz_uint32((FLAC__uint32)(word>>32)) :
+		FLAC__clz_uint32((FLAC__uint32)word) + 32;
+}
+
+static inline uint32_t FLAC__clz_uint64(FLAC__uint64 v)
+{
+	/* Never used with input 0 */
+	FLAC__ASSERT(v > 0);
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+	return __builtin_clzll(v);
+#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
+	{
+		uint32_t idx;
+		_BitScanReverse64(&idx, v);
+		return idx ^ 63U;
+	}
+#else
+	return FLAC__clz_soft_uint64(v);
+#endif
+}
+
+/* These two functions work with input 0 */
+static inline uint32_t FLAC__clz2_uint32(FLAC__uint32 v)
+{
+	if (!v)
+		return 32;
+	return FLAC__clz_uint32(v);
+}
+
+static inline uint32_t FLAC__clz2_uint64(FLAC__uint64 v)
+{
+	if (!v)
+		return 64;
+	return FLAC__clz_uint64(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 uint32_t FLAC__bitmath_ilog2(FLAC__uint32 v)
+{
+	FLAC__ASSERT(v > 0);
+#if defined(__INTEL_COMPILER)
+	return _bit_scan_reverse(v);
+#elif defined(_MSC_VER)
+	{
+		uint32_t idx;
+		_BitScanReverse(&idx, v);
+		return idx;
+	}
+#else
+	return FLAC__clz_uint32(v) ^ 31U;
+#endif
+}
+
+static inline uint32_t FLAC__bitmath_ilog2_wide(FLAC__uint64 v)
+{
+	FLAC__ASSERT(v > 0);
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+	return __builtin_clzll(v) ^ 63U;
+/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */
+#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
+	{
+		uint32_t 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 (tterribe@xiph.org) 2001-2009 CC0 (Public domain).
+*/
+	{
+		static const uint8_t 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*FLAC__U64L(0x218A392CD3D5DBF)>>58&0x3F];
+	}
+#endif
+}
+
+uint32_t FLAC__bitmath_silog2(FLAC__int64 v);
+
+#endif
diff --git a/src/libFLAC/include/private/bitreader.h b/src/libFLAC/include/private/bitreader.h
new file mode 100644
index 0000000..585a5db
--- /dev/null
+++ b/src/libFLAC/include/private/bitreader.h
@@ -0,0 +1,91 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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);
+uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+uint32_t 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, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t 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, uint32_t 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, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val);
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter);
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter);
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter);
+#endif
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen);
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen);
+#endif
diff --git a/src/libFLAC/include/private/bitwriter.h b/src/libFLAC/include/private/bitwriter.h
new file mode 100644
index 0000000..672f282
--- /dev/null
+++ b/src/libFLAC/include/private/bitwriter.h
@@ -0,0 +1,104 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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);
+uint32_t 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, uint32_t bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits);
+FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t 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[], uint32_t nvals);
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, uint32_t val);
+uint32_t FLAC__bitwriter_rice_bits(FLAC__int32 val, uint32_t parameter);
+#if 0 /* UNUSED */
+uint32_t FLAC__bitwriter_golomb_bits_signed(int val, uint32_t parameter);
+uint32_t FLAC__bitwriter_golomb_bits_unsigned(uint32_t val, uint32_t parameter);
+#endif
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t parameter);
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, uint32_t nvals, uint32_t parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, uint32_t parameter);
+FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, uint32_t val, uint32_t 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
diff --git a/src/libFLAC/include/private/cpu.h b/src/libFLAC/include/private/cpu.h
new file mode 100644
index 0000000..fc31350
--- /dev/null
+++ b/src/libFLAC/include/private/cpu.h
@@ -0,0 +1,195 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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__CPU_H
+#define FLAC__PRIVATE__CPU_H
+
+#include "FLAC/ordinals.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef FLAC__CPU_X86_64
+
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
+#define FLAC__CPU_X86_64
+#endif
+
+#endif
+
+#ifndef FLAC__CPU_IA32
+
+#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)
+#define FLAC__CPU_IA32
+#endif
+
+#endif
+
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#if 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 __clang__ && __has_attribute(__target__) /* clang */
+  #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x)))
+  #if __has_builtin(__builtin_ia32_maxps)
+    #define FLAC__SSE_SUPPORTED 1
+  #endif
+  #if __has_builtin(__builtin_ia32_pmuludq128)
+    #define FLAC__SSE2_SUPPORTED 1
+  #endif
+  #if __has_builtin(__builtin_ia32_pabsd128)
+    #define FLAC__SSSE3_SUPPORTED 1
+  #endif
+  #if __has_builtin(__builtin_ia32_pmuldq128)
+    #define FLAC__SSE4_1_SUPPORTED 1
+  #endif
+  #if __has_builtin(__builtin_ia32_pabsd256)
+    #define FLAC__AVX2_SUPPORTED 1
+  #endif
+#elif defined __GNUC__ && !defined __clang__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* GCC 4.9+ */
+  #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
+  #ifdef FLAC__USE_AVX
+    #define FLAC__AVX_SUPPORTED 1
+    #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
+#else
+  #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 /* compiler version */
+#endif /* intrinsics support */
+
+
+#ifndef FLAC__AVX_SUPPORTED
+#define FLAC__AVX_SUPPORTED 0
+#endif
+
+typedef enum {
+	FLAC__CPUINFO_TYPE_IA32,
+	FLAC__CPUINFO_TYPE_X86_64,
+	FLAC__CPUINFO_TYPE_PPC,
+	FLAC__CPUINFO_TYPE_UNKNOWN
+} FLAC__CPUInfo_Type;
+
+typedef struct {
+	FLAC__bool intel;
+
+	FLAC__bool cmov;
+	FLAC__bool mmx;
+	FLAC__bool sse;
+	FLAC__bool sse2;
+
+	FLAC__bool sse3;
+	FLAC__bool ssse3;
+	FLAC__bool sse41;
+	FLAC__bool sse42;
+	FLAC__bool avx;
+	FLAC__bool avx2;
+	FLAC__bool fma;
+} FLAC__CPUInfo_x86;
+
+typedef struct {
+	FLAC__bool arch_3_00;
+	FLAC__bool arch_2_07;
+} FLAC__CPUInfo_ppc;
+
+typedef struct {
+	FLAC__bool use_asm;
+	FLAC__CPUInfo_Type type;
+	FLAC__CPUInfo_x86 x86;
+	FLAC__CPUInfo_ppc ppc;
+} FLAC__CPUInfo;
+
+void FLAC__cpu_info(FLAC__CPUInfo *info);
+
+FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void);
+
+void         FLAC__cpu_info_asm_ia32(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx);
+
+#endif
diff --git a/src/libFLAC/include/private/crc.h b/src/libFLAC/include/private/crc.h
new file mode 100644
index 0000000..5fc7e5e
--- /dev/null
+++ b/src/libFLAC/include/private/crc.h
@@ -0,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  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__CRC_H
+#define FLAC__PRIVATE__CRC_H
+
+#include "FLAC/ordinals.h"
+
+/* 8 bit CRC generator, MSB shifted first
+** polynomial = x^8 + x^2 + x^1 + x^0
+** init = 0
+*/
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len);
+
+/* 16 bit CRC generator, MSB shifted first
+** polynomial = x^16 + x^15 + x^2 + x^0
+** init = 0
+*/
+extern FLAC__uint16 const FLAC__crc16_table[8][256];
+
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[0][((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[0][((crc)>>8) ^ (data)]) & 0xffff)
+#endif
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len);
+FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc);
+FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc);
+
+#endif
diff --git a/src/libFLAC/include/private/fixed.h b/src/libFLAC/include/private/fixed.h
new file mode 100644
index 0000000..9edf0ab
--- /dev/null
+++ b/src/libFLAC/include/private/fixed.h
@@ -0,0 +1,107 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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__FIXED_H
+#define FLAC__PRIVATE__FIXED_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()
+ *	--------------------------------------------------------------------
+ *	Compute the best fixed predictor and the expected bits-per-sample
+ *  of the residual signal for each order.  The _wide() version uses
+ *  64-bit integers which is statistically necessary when bits-per-
+ *  sample + log2(blocksize) > 30
+ *
+ *	IN data[0,data_len-1]
+ *	IN data_len
+ *	OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER]
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# ifndef FLAC__NO_ASM
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#   ifdef FLAC__SSE2_SUPPORTED
+uint32_t FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]);
+uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]);
+#   endif
+#   ifdef FLAC__SSSE3_SUPPORTED
+uint32_t FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]);
+#   endif
+#  endif
+#  if defined FLAC__CPU_IA32 && defined FLAC__HAS_NASM
+uint32_t FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#  endif
+# endif
+#else
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#endif
+
+/*
+ *	FLAC__fixed_compute_residual()
+ *	--------------------------------------------------------------------
+ *	Compute the residual signal obtained from sutracting the predicted
+ *	signal from the original.
+ *
+ *	IN data[-order,data_len-1]        original signal (NOTE THE INDICES!)
+ *	IN data_len                       length of original signal
+ *	IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ *	OUT residual[0,data_len-1]        residual signal
+ */
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]);
+
+/*
+ *	FLAC__fixed_restore_signal()
+ *	--------------------------------------------------------------------
+ *	Restore the original signal by summing the residual and the
+ *	predictor.
+ *
+ *	IN residual[0,data_len-1]         residual signal
+ *	IN data_len                       length of original signal
+ *	IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ *	*** IMPORTANT: the caller must pass in the historical samples:
+ *	IN  data[-order,-1]               previously-reconstructed historical samples
+ *	OUT data[0,data_len-1]            original signal
+ */
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]);
+
+#endif
diff --git a/src/libFLAC/include/private/float.h b/src/libFLAC/include/private/float.h
new file mode 100644
index 0000000..cb32da4
--- /dev/null
+++ b/src/libFLAC/include/private/float.h
@@ -0,0 +1,95 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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"
+
+/*
+ * All the code in libFLAC that uses float and double
+ * should be protected by checks of the macro
+ * FLAC__INTEGER_ONLY_LIBRARY.
+ *
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+/*
+ * FLAC__real is the basic floating point type used in LPC analysis.
+ *
+ * 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 (uint32_t)(-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, uint32_t fracbits, uint32_t precision);
+
+#endif
+
+#endif
diff --git a/src/libFLAC/include/private/format.h b/src/libFLAC/include/private/format.h
new file mode 100644
index 0000000..8f28017
--- /dev/null
+++ b/src/libFLAC/include/private/format.h
@@ -0,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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__FORMAT_H
+#define FLAC__PRIVATE__FORMAT_H
+
+#include "FLAC/format.h"
+
+uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order);
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize);
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order);
+
+#endif
diff --git a/src/libFLAC/include/private/lpc.h b/src/libFLAC/include/private/lpc.h
new file mode 100644
index 0000000..64dfd1f
--- /dev/null
+++ b/src/libFLAC/include/private/lpc.h
@@ -0,0 +1,263 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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__LPC_H
+#define FLAC__PRIVATE__LPC_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[], uint32_t data_len);
+
+/*
+ *	FLAC__lpc_compute_autocorrelation()
+ *	--------------------------------------------------------------------
+ *	Compute the autocorrelation for lags between 0 and lag-1.
+ *	Assumes data[] outside of [0,data_len-1] == 0.
+ *	Asserts that lag > 0.
+ *
+ *	IN data[0,data_len-1]
+ *	IN data_len
+ *	IN 0 < lag <= data_len
+ *	OUT autoc[0,lag-1]
+ */
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#    endif
+#  endif
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE_SUPPORTED
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#    endif
+#  endif
+#if defined(FLAC__CPU_PPC64) && defined(FLAC__USE_VSX)
+#ifdef FLAC__HAS_TARGET_POWER9
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#endif
+#ifdef FLAC__HAS_TARGET_POWER8
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#endif
+#endif
+#endif
+
+/*
+ *	FLAC__lpc_compute_lp_coefficients()
+ *	--------------------------------------------------------------------
+ *	Computes LP coefficients for orders 1..max_order.
+ *	Do not call if autoc[0] == 0.0.  This means the signal is zero
+ *	and there is no point in calculating a predictor.
+ *
+ *	IN autoc[0,max_order]                      autocorrelation values
+ *	IN 0 < max_order <= FLAC__MAX_LPC_ORDER    max LP order to compute
+ *	OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order
+ *	*** IMPORTANT:
+ *	*** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched
+ *	OUT error[0,max_order-1]                   error for each order (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[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]);
+
+/*
+ *	FLAC__lpc_quantize_coefficients()
+ *	--------------------------------------------------------------------
+ *	Quantizes the LP coefficients.  NOTE: precision + bits_per_sample
+ *	must be less than 32 (sizeof(FLAC__int32)*8).
+ *
+ *	IN lp_coeff[0,order-1]    LP coefficients
+ *	IN order                  LP order
+ *	IN FLAC__MIN_QLP_COEFF_PRECISION < precision
+ *	                          desired precision (in bits, including sign
+ *	                          bit) of largest coefficient
+ *	OUT qlp_coeff[0,order-1]  quantized coefficients
+ *	OUT shift                 # of bits to shift right to get approximated
+ *	                          LP coefficients.  NOTE: could be negative.
+ *	RETURN 0 => quantization OK
+ *	       1 => coefficients require too much shifting for *shift to
+ *              fit in the LPC subframe header.  'shift' is unset.
+ *         2 => coefficients are all zero, which is bad.  'shift' is
+ *              unset.
+ */
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift);
+
+/*
+ *	FLAC__lpc_compute_residual_from_qlp_coefficients()
+ *	--------------------------------------------------------------------
+ *	Compute the residual signal obtained from sutracting the predicted
+ *	signal from the original.
+ *
+ *	IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ *	IN data_len                length of original signal
+ *	IN qlp_coeff[0,order-1]    quantized LP coefficients
+ *	IN order > 0               LP order
+ *	IN lp_quantization         quantization of LP coefficients in bits
+ *	OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t 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, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#  endif
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t 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, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t 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, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#  endif
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+/*
+ *	FLAC__lpc_restore_signal()
+ *	--------------------------------------------------------------------
+ *	Restore the original signal by summing the residual and the
+ *	predictor.
+ *
+ *	IN residual[0,data_len-1]  residual signal
+ *	IN data_len                length of original signal
+ *	IN qlp_coeff[0,order-1]    quantized LP coefficients
+ *	IN order > 0               LP order
+ *	IN lp_quantization         quantization of LP coefficients in bits
+ *	*** IMPORTANT: the caller must pass in the historical samples:
+ *	IN  data[-order,-1]        previously-reconstructed historical samples
+ *	OUT data[0,data_len-1]     original signal
+ */
+void FLAC__lpc_restore_signal(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide_asm_ia32(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t 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) && FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE4_1_SUPPORTED
+void FLAC__lpc_restore_signal_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_16_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t 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()
+ *	--------------------------------------------------------------------
+ *	Compute the expected number of bits per residual signal sample
+ *	based on the LP error (which is related to the residual variance).
+ *
+ *	IN lpc_error >= 0.0   error returned from calculating LP coefficients
+ *	IN total_samples > 0  # of samples in residual signal
+ *	RETURN                expected bits per sample
+ */
+double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples);
+double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale);
+
+/*
+ *	FLAC__lpc_compute_best_order()
+ *	--------------------------------------------------------------------
+ *	Compute the best order from the array of signal errors returned
+ *	during coefficient computation.
+ *
+ *	IN lpc_error[0,max_order-1] >= 0.0  error returned from calculating LP coefficients
+ *	IN max_order > 0                    max LP order
+ *	IN total_samples > 0                # of samples in residual signal
+ *	IN 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
+ */
+uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
diff --git a/src/libFLAC/include/private/macros.h b/src/libFLAC/include/private/macros.h
new file mode 100644
index 0000000..3a8072e
--- /dev/null
+++ b/src/libFLAC/include/private/macros.h
@@ -0,0 +1,74 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2016  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
+
+#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>
+#if defined(MIN) && defined(MAX)
+#define flac_max(a,b) MAX(a,b)
+#define flac_min(a,b) MIN(a,b)
+#endif
+
+/* 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 flac_min
+#define flac_min(x,y)	((x) <= (y) ? (x) : (y))
+#endif
+
+#ifndef flac_max
+#define flac_max(x,y)	((x) >= (y) ? (x) : (y))
+#endif
+
+#endif
diff --git a/src/libFLAC/include/private/md5.h b/src/libFLAC/include/private/md5.h
new file mode 100644
index 0000000..f9d79c3
--- /dev/null
+++ b/src/libFLAC/include/private/md5.h
@@ -0,0 +1,50 @@
+#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
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain, with no warranty.
+ */
+
+#include "FLAC/ordinals.h"
+
+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__multibyte internal_buf;
+	size_t capacity;
+} FLAC__MD5Context;
+
+void FLAC__MD5Init(FLAC__MD5Context *context);
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context);
+
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample);
+
+#endif
diff --git a/src/libFLAC/include/private/memory.h b/src/libFLAC/include/private/memory.h
new file mode 100644
index 0000000..a6d3faf
--- /dev/null
+++ b/src/libFLAC/include/private/memory.h
@@ -0,0 +1,58 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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__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.
+ * 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(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, uint32_t **unaligned_pointer, uint32_t **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
diff --git a/libFLAC/include/private/metadata.h b/src/libFLAC/include/private/metadata.h
similarity index 100%
rename from libFLAC/include/private/metadata.h
rename to src/libFLAC/include/private/metadata.h
diff --git a/src/libFLAC/include/private/ogg_decoder_aspect.h b/src/libFLAC/include/private/ogg_decoder_aspect.h
new file mode 100644
index 0000000..0a8534d
--- /dev/null
+++ b/src/libFLAC/include/private/ogg_decoder_aspect.h
@@ -0,0 +1,80 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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;
+	uint32_t 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
diff --git a/src/libFLAC/include/private/ogg_encoder_aspect.h b/src/libFLAC/include/private/ogg_encoder_aspect.h
new file mode 100644
index 0000000..f3c95f9
--- /dev/null
+++ b/src/libFLAC/include/private/ogg_encoder_aspect.h
@@ -0,0 +1,63 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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;
+	uint32_t 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, uint32_t 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, uint32_t samples, uint32_t current_frame, void *client_data);
+
+FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data);
+#endif
diff --git a/libFLAC/include/private/ogg_helper.h b/src/libFLAC/include/private/ogg_helper.h
similarity index 100%
rename from libFLAC/include/private/ogg_helper.h
rename to src/libFLAC/include/private/ogg_helper.h
diff --git a/src/libFLAC/include/private/ogg_mapping.h b/src/libFLAC/include/private/ogg_mapping.h
new file mode 100644
index 0000000..6eb609e
--- /dev/null
+++ b/src/libFLAC/include/private/ogg_mapping.h
@@ -0,0 +1,64 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 uint32_t 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 uint32_t FLAC__OGG_MAPPING_VERSION_MAJOR_LEN; /* = 8 bits */
+extern const uint32_t 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 uint32_t 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
diff --git a/src/libFLAC/include/private/stream_encoder.h b/src/libFLAC/include/private/stream_encoder.h
new file mode 100644
index 0000000..ade648b
--- /dev/null
+++ b/src/libFLAC/include/private/stream_encoder.h
@@ -0,0 +1,67 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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[],
+			uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t 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[],
+			uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t 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[],
+			uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps);
+#endif
+
+#endif
+
+#endif
diff --git a/src/libFLAC/include/private/stream_encoder_framing.h b/src/libFLAC/include/private/stream_encoder_framing.h
new file mode 100644
index 0000000..8df1049
--- /dev/null
+++ b/src/libFLAC/include/private/stream_encoder_framing.h
@@ -0,0 +1,46 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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_FRAMING_H
+#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
+
+#include "FLAC/format.h"
+#include "bitwriter.h"
+
+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, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, uint32_t samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw);
+
+#endif
diff --git a/libFLAC/include/private/window.h b/src/libFLAC/include/private/window.h
similarity index 100%
rename from libFLAC/include/private/window.h
rename to src/libFLAC/include/private/window.h
diff --git a/src/libFLAC/include/protected/Makefile.am b/src/libFLAC/include/protected/Makefile.am
new file mode 100644
index 0000000..d9c6476
--- /dev/null
+++ b/src/libFLAC/include/protected/Makefile.am
@@ -0,0 +1,35 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  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.
+
+noinst_HEADERS = \
+	all.h \
+	stream_decoder.h \
+	stream_encoder.h
diff --git a/libFLAC/include/protected/all.h b/src/libFLAC/include/protected/all.h
similarity index 100%
rename from libFLAC/include/protected/all.h
rename to src/libFLAC/include/protected/all.h
diff --git a/src/libFLAC/include/protected/stream_decoder.h b/src/libFLAC/include/protected/stream_decoder.h
new file mode 100644
index 0000000..2f3996b
--- /dev/null
+++ b/src/libFLAC/include/protected/stream_decoder.h
@@ -0,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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__PROTECTED__STREAM_DECODER_H
+#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;
+	uint32_t channels;
+	FLAC__ChannelAssignment channel_assignment;
+	uint32_t bits_per_sample;
+	uint32_t sample_rate; /* in Hz */
+	uint32_t 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;
+
+/*
+ * Return the number of input bytes consumed
+ */
+uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder);
+
+#endif
diff --git a/src/libFLAC/include/protected/stream_encoder.h b/src/libFLAC/include/protected/stream_encoder.h
new file mode 100644
index 0000000..c290904
--- /dev/null
+++ b/src/libFLAC/include/protected/stream_encoder.h
@@ -0,0 +1,118 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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__PROTECTED__STREAM_ENCODER_H
+#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 // #ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+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;
+	uint32_t channels;
+	uint32_t bits_per_sample;
+	uint32_t sample_rate;
+	uint32_t blocksize;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	uint32_t num_apodizations;
+	FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS];
+#endif
+	uint32_t max_lpc_order;
+	uint32_t qlp_coeff_precision;
+	FLAC__bool do_qlp_coeff_prec_search;
+	FLAC__bool do_exhaustive_model_search;
+	FLAC__bool do_escape_coding;
+	uint32_t min_residual_partition_order;
+	uint32_t max_residual_partition_order;
+	uint32_t rice_parameter_search_dist;
+	FLAC__uint64 total_samples_estimate;
+	FLAC__StreamMetadata **metadata;
+	uint32_t num_metadata_blocks;
+	FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset;
+#if FLAC__HAS_OGG
+	FLAC__OggEncoderAspect ogg_encoder_aspect;
+#endif
+} FLAC__StreamEncoderProtected;
+
+#endif
diff --git a/src/libFLAC/libFLAC.m4 b/src/libFLAC/libFLAC.m4
new file mode 100644
index 0000000..9bf2bf3
--- /dev/null
+++ b/src/libFLAC/libFLAC.m4
@@ -0,0 +1,118 @@
+# Configure paths for libFLAC
+# "Inspired" by ogg.m4
+
+dnl AM_PATH_LIBFLAC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libFLAC, and define LIBFLAC_CFLAGS, LIBFLAC_LIBS, LIBFLAC_LIBDIR
+dnl
+AC_DEFUN([AM_PATH_LIBFLAC],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(libFLAC,[  --with-libFLAC=PFX   Prefix where libFLAC is installed (optional)], libFLAC_prefix="$withval", libFLAC_prefix="")
+AC_ARG_WITH(libFLAC-libraries,[  --with-libFLAC-libraries=DIR   Directory where libFLAC library is installed (optional)], libFLAC_libraries="$withval", libFLAC_libraries="")
+AC_ARG_WITH(libFLAC-includes,[  --with-libFLAC-includes=DIR   Directory where libFLAC header files are installed (optional)], libFLAC_includes="$withval", libFLAC_includes="")
+AC_ARG_ENABLE(libFLACtest, [  --disable-libFLACtest       Do not try to compile and run a test libFLAC program],, enable_libFLACtest=yes)
+
+  if test "x$libFLAC_libraries" != "x" ; then
+    LIBFLAC_LIBS="-L$libFLAC_libraries"
+  elif test "x$libFLAC_prefix" = "xno" || test "x$libFLAC_prefix" = "xyes" ; then
+    LIBFLAC_LIBS=""
+  elif test "x$libFLAC_prefix" != "x" ; then
+    LIBFLAC_LIBS="-L$libFLAC_prefix/lib"
+  elif test "x$prefix" != "xNONE"; then
+    LIBFLAC_LIBS="-L$prefix/lib"
+  fi
+
+  if test "x$libFLAC_prefix" != "xno" ; then
+    LIBFLAC_LIBS="$LIBFLAC_LIBS -lFLAC $OGG_LIBS -lm"
+  fi
+
+  if test "x$libFLAC_includes" != "x" ; then
+    LIBFLAC_CFLAGS="-I$libFLAC_includes"
+  elif test "x$libFLAC_prefix" != "x" ; then
+    LIBFLAC_CFLAGS="-I$libFLAC_prefix/include"
+  elif test "$prefix" != "xNONE"; then
+    LIBFLAC_CFLAGS=""
+  fi
+
+  AC_MSG_CHECKING(for libFLAC)
+  no_libFLAC=""
+
+
+  if test "x$enable_libFLACtest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_CXXFLAGS="$CXXFLAGS"
+    ac_save_LIBS="$LIBS"
+    ac_save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
+    CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
+    CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
+    LIBS="$LIBS $LIBFLAC_LIBS"
+    LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+dnl
+dnl Now check if the installed libFLAC is sufficiently new.
+dnl
+      rm -f conf.libFLACtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FLAC/format.h>
+
+int main ()
+{
+  system("touch conf.libFLACtest");
+  return 0;
+}
+
+],, no_libFLAC=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       CXXFLAGS="$ac_save_CXXFLAGS"
+       LIBS="$ac_save_LIBS"
+       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+  fi
+
+  if test "x$no_libFLAC" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.libFLACtest ; then
+       :
+     else
+       echo "*** Could not run libFLAC test program, checking why..."
+       CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
+       CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
+       LIBS="$LIBS $LIBFLAC_LIBS"
+       LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <FLAC/format.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding libFLAC or finding the wrong"
+       echo "*** version of libFLAC. If it is not finding libFLAC, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occurred. This usually means libFLAC was incorrectly installed"
+       echo "*** or that you have moved libFLAC since it was installed. In the latter case, you"
+       echo "*** may want to edit the libFLAC-config script: $LIBFLAC_CONFIG" ])
+       CFLAGS="$ac_save_CFLAGS"
+       CXXFLAGS="$ac_save_CXXFLAGS"
+       LIBS="$ac_save_LIBS"
+       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+     fi
+     LIBFLAC_CFLAGS=""
+     LIBFLAC_LIBDIR=""
+     LIBFLAC_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(LIBFLAC_CFLAGS)
+  AC_SUBST(LIBFLAC_LIBDIR)
+  AC_SUBST(LIBFLAC_LIBS)
+  rm -f conf.libFLACtest
+])
diff --git a/src/libFLAC/libFLAC_blocklist.txt b/src/libFLAC/libFLAC_blocklist.txt
new file mode 100644
index 0000000..9c4ed6d
--- /dev/null
+++ b/src/libFLAC/libFLAC_blocklist.txt
@@ -0,0 +1,23 @@
+[integer]
+# Preemptive due to: while(lag--)
+fun:FLAC__lpc_compute_autocorrelation
+# libFLAC/stream_encoder.c:3982: 4294967292 + 128 cannot be represented in type 'unsigned int'
+fun:precompute_partition_info_sums_
+# libFLAC/lpc.c:1030:18: -1932902714 + -1376235516 cannot be represented in type 'int'
+fun:FLAC__lpc_restore_signal
+# libFLAC/fixed.c:390:44: 6 * -358419632 cannot be represented in type 'int'
+# libFLAC/fixed.c:378:27: -1023409921 + -1145670695 cannot be represented in type 'int'
+# libFLAC/stream_decoder.c:2102:39: 13408450 + 2135505484 cannot be represented in type 'int'
+
+fun:FLAC__fixed_restore_signal
+fun:FLAC__fixed_compute_residual
+fun:read_frame_
+
+src:*/libFLAC/crc.c
+src:*/libFLAC/md5.c
+src:*/libFLAC/bitmath.c
+src:*/libFLAC/bitreader.c
+src:*/libFLAC/bitwriter.c
+
+# Performance related
+fun:FLAC__lpc_restore_signal_wide
diff --git a/src/libFLAC/libFLAC_dynamic.vcproj b/src/libFLAC/libFLAC_dynamic.vcproj
new file mode 100644
index 0000000..4cae1aa
--- /dev/null
+++ b/src/libFLAC/libFLAC_dynamic.vcproj
@@ -0,0 +1,560 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="libFLAC_dynamic"

+	ProjectGUID="{4cefbc83-c215-11db-8314-0800200c9a66}"

+	RootNamespace="libFLAC_dynamic"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)_dynamic"

+			ConfigurationType="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				AdditionalOptions="/D &quot;_USE_MATH_DEFINES&quot;"

+				Optimization="0"

+				EnableIntrinsicFunctions="true"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FLAC_API_EXPORTS;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION=\&quot;1.3.3\&quot;;DEBUG;FLAC__OVERFLOW_DETECT"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)_dynamic"

+			ConfigurationType="2"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				AdditionalOptions="/D &quot;_USE_MATH_DEFINES&quot;"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FLAC_API_EXPORTS;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION=\&quot;1.3.3\&quot;;FLaC__INLINE=_inline"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\include\protected\all.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\all.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\bitmath.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\bitreader.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\bitwriter.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\cpu.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\crc.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\fixed.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\float.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\format.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\lpc.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\md5.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\memory.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\metadata.h"

+				>

+			</File>

+			<File

+				RelativePath=".\ia32\nasm.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\ogg_decoder_aspect.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\ogg_encoder_aspect.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\ogg_helper.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\ogg_mapping.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\protected\stream_decoder.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\stream_encoder.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\protected\stream_encoder.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\stream_encoder_framing.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\window.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\bitmath.c"

+				>

+			</File>

+			<File

+				RelativePath=".\bitreader.c"

+				>

+			</File>

+			<File

+				RelativePath=".\bitwriter.c"

+				>

+			</File>

+			<File

+				RelativePath=".\cpu.c"

+				>

+			</File>

+			<File

+				RelativePath=".\crc.c"

+				>

+			</File>

+			<File

+				RelativePath=".\fixed.c"

+				>

+			</File>

+			<File

+				RelativePath=".\fixed_intrin_sse2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\fixed_intrin_ssse3.c"

+				>

+			</File>

+			<File

+				RelativePath=".\float.c"

+				>

+			</File>

+			<File

+				RelativePath=".\format.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc_intrin_sse.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc_intrin_sse2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc_intrin_sse41.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc_intrin_avx2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\md5.c"

+				>

+			</File>

+			<File

+				RelativePath=".\memory.c"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_iterators.c"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_object.c"

+				>

+			</File>

+			<File

+				RelativePath=".\ogg_decoder_aspect.c"

+				>

+			</File>

+			<File

+				RelativePath=".\ogg_encoder_aspect.c"

+				>

+			</File>

+			<File

+				RelativePath=".\ogg_helper.c"

+				>

+			</File>

+			<File

+				RelativePath=".\ogg_mapping.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_decoder.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder_framing.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder_intrin_sse2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder_intrin_ssse3.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder_intrin_avx2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\window.c"

+				>

+			</File>

+			<File

+				RelativePath=".\windows_unicode_filenames.c"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\include\FLAC\all.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\alloc.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\assert.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\callback.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\compat.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\endswap.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\export.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\format.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\macros.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\metadata.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\ordinals.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\private.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\safe_str.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\stream_decoder.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\stream_encoder.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\windows_unicode_filenames.h"

+				>

+			</File>

+		</Filter>

+		<File

+			RelativePath=".\ia32\cpu_asm.nasm"

+			>

+			<FileConfiguration

+				Name="Debug|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/cpu_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/cpu_asm.obj"

+				/>

+			</FileConfiguration>

+			<FileConfiguration

+				Name="Release|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/cpu_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/cpu_asm.obj"

+				/>

+			</FileConfiguration>

+		</File>

+		<File

+			RelativePath=".\ia32\fixed_asm.nasm"

+			>

+			<FileConfiguration

+				Name="Debug|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/fixed_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/fixed_asm.obj"

+				/>

+			</FileConfiguration>

+			<FileConfiguration

+				Name="Release|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/fixed_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/fixed_asm.obj"

+				/>

+			</FileConfiguration>

+		</File>

+		<File

+			RelativePath=".\ia32\lpc_asm.nasm"

+			>

+			<FileConfiguration

+				Name="Debug|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/lpc_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/lpc_asm.obj"

+				/>

+			</FileConfiguration>

+			<FileConfiguration

+				Name="Release|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/lpc_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/lpc_asm.obj"

+				/>

+			</FileConfiguration>

+		</File>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/libFLAC/libFLAC_dynamic.vcxproj b/src/libFLAC/libFLAC_dynamic.vcxproj
new file mode 100644
index 0000000..3c0c10e
--- /dev/null
+++ b/src/libFLAC/libFLAC_dynamic.vcxproj
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc83-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>libFLAC_dynamic</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+    <IntDir>$(Configuration)_dynamic\</IntDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+    <IntDir>$(Platform)\$(Configuration)_dynamic\</IntDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+    <IntDir>$(Configuration)_dynamic\</IntDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+    <IntDir>$(Platform)\$(Configuration)_dynamic\</IntDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <AdditionalOptions>/D "_USE_MATH_DEFINES" %(AdditionalOptions)</AdditionalOptions>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FLAC_API_EXPORTS;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION="1.3.3";DEBUG;FLAC__OVERFLOW_DETECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <AdditionalOptions>/D "_USE_MATH_DEFINES" %(AdditionalOptions)</AdditionalOptions>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FLAC_API_EXPORTS;FLAC__HAS_OGG;ENABLE_64_BIT_WORDS;FLAC__CPU_X86_64;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION="1.3.3";DEBUG;FLAC__OVERFLOW_DETECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <AdditionalOptions>/D "_USE_MATH_DEFINES" %(AdditionalOptions)</AdditionalOptions>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FLAC_API_EXPORTS;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION="1.3.3";FLaC__INLINE=_inline;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+      <FloatingPointModel>Fast</FloatingPointModel>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <AdditionalOptions>/D "_USE_MATH_DEFINES" %(AdditionalOptions)</AdditionalOptions>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FLAC_API_EXPORTS;FLAC__HAS_OGG;ENABLE_64_BIT_WORDS;FLAC__CPU_X86_64;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION="1.3.3";FLaC__INLINE=_inline;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+      <FloatingPointModel>Fast</FloatingPointModel>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Windows</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\include\FLAC\all.h" />

+    <ClInclude Include="..\..\include\FLAC\assert.h" />

+    <ClInclude Include="..\..\include\FLAC\callback.h" />

+    <ClInclude Include="..\..\include\FLAC\export.h" />

+    <ClInclude Include="..\..\include\FLAC\format.h" />

+    <ClInclude Include="..\..\include\FLAC\metadata.h" />

+    <ClInclude Include="..\..\include\FLAC\ordinals.h" />

+    <ClInclude Include="..\..\include\FLAC\stream_decoder.h" />

+    <ClInclude Include="..\..\include\FLAC\stream_encoder.h" />

+    <ClInclude Include="..\..\include\share\alloc.h" />

+    <ClInclude Include="..\..\include\share\compat.h" />

+    <ClInclude Include="..\..\include\share\endswap.h" />

+    <ClInclude Include="..\..\include\share\macros.h" />

+    <ClInclude Include="..\..\include\share\private.h" />

+    <ClInclude Include="..\..\include\share\safe_str.h" />

+    <ClInclude Include="..\..\include\share\windows_unicode_filenames.h" />

+    <ClInclude Include="ia32\nasm.h" />

+    <ClInclude Include="include\private\all.h" />

+    <ClInclude Include="include\private\bitmath.h" />

+    <ClInclude Include="include\private\bitreader.h" />

+    <ClInclude Include="include\private\bitwriter.h" />

+    <ClInclude Include="include\private\cpu.h" />

+    <ClInclude Include="include\private\crc.h" />

+    <ClInclude Include="include\private\fixed.h" />

+    <ClInclude Include="include\private\float.h" />

+    <ClInclude Include="include\private\format.h" />

+    <ClInclude Include="include\private\lpc.h" />

+    <ClInclude Include="include\private\md5.h" />

+    <ClInclude Include="include\private\memory.h" />

+    <ClInclude Include="include\private\metadata.h" />

+    <ClInclude Include="include\private\ogg_decoder_aspect.h" />

+    <ClInclude Include="include\private\ogg_encoder_aspect.h" />

+    <ClInclude Include="include\private\ogg_helper.h" />

+    <ClInclude Include="include\private\ogg_mapping.h" />

+    <ClInclude Include="include\private\stream_encoder.h" />

+    <ClInclude Include="include\private\stream_encoder_framing.h" />

+    <ClInclude Include="include\private\window.h" />

+    <ClInclude Include="include\protected\all.h" />

+    <ClInclude Include="include\protected\stream_decoder.h" />

+    <ClInclude Include="include\protected\stream_encoder.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="bitmath.c" />

+    <ClCompile Include="bitreader.c" />

+    <ClCompile Include="bitwriter.c" />

+    <ClCompile Include="cpu.c" />

+    <ClCompile Include="crc.c" />

+    <ClCompile Include="fixed.c" />

+    <ClCompile Include="fixed_intrin_sse2.c" />

+    <ClCompile Include="fixed_intrin_ssse3.c" />

+    <ClCompile Include="float.c" />

+    <ClCompile Include="format.c" />

+    <ClCompile Include="lpc.c" />

+    <ClCompile Include="lpc_intrin_avx2.c">

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_sse.c" />

+    <ClCompile Include="lpc_intrin_sse2.c" />

+    <ClCompile Include="lpc_intrin_sse41.c" />

+    <ClCompile Include="md5.c" />

+    <ClCompile Include="memory.c" />

+    <ClCompile Include="metadata_iterators.c" />

+    <ClCompile Include="metadata_object.c" />

+    <ClCompile Include="ogg_decoder_aspect.c" />

+    <ClCompile Include="ogg_encoder_aspect.c" />

+    <ClCompile Include="ogg_helper.c" />

+    <ClCompile Include="ogg_mapping.c" />

+    <ClCompile Include="stream_decoder.c" />

+    <ClCompile Include="stream_encoder.c" />

+    <ClCompile Include="stream_encoder_framing.c" />

+    <ClCompile Include="stream_encoder_intrin_avx2.c">

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_intrin_sse2.c" />

+    <ClCompile Include="stream_encoder_intrin_ssse3.c" />

+    <ClCompile Include="window.c" />

+    <ClCompile Include="windows_unicode_filenames.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="ia32\cpu_asm.nasm">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/cpu_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/cpu_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/cpu_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/cpu_asm.obj;%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/cpu_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/cpu_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/cpu_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/cpu_asm.obj;%(Outputs)</Outputs>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

+    </CustomBuild>

+    <CustomBuild Include="ia32\fixed_asm.nasm">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/fixed_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/fixed_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/fixed_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/fixed_asm.obj;%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/fixed_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/fixed_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/fixed_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/fixed_asm.obj;%(Outputs)</Outputs>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

+    </CustomBuild>

+    <CustomBuild Include="ia32\lpc_asm.nasm">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/lpc_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/lpc_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/lpc_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/lpc_asm.obj;%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/lpc_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/lpc_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/lpc_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/lpc_asm.obj;%(Outputs)</Outputs>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

+    </CustomBuild>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/libFLAC/libFLAC_dynamic.vcxproj.filters b/src/libFLAC/libFLAC_dynamic.vcxproj.filters
new file mode 100644
index 0000000..875c021
--- /dev/null
+++ b/src/libFLAC/libFLAC_dynamic.vcxproj.filters
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{c048646d-1833-4a52-9849-022db831cc79}</UniqueIdentifier>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="include\private\all.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\protected\all.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\bitmath.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\bitreader.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\bitwriter.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\cpu.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\crc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\fixed.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\float.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\format.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\lpc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\md5.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\memory.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\metadata.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ia32\nasm.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\ogg_decoder_aspect.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\ogg_encoder_aspect.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\ogg_helper.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\ogg_mapping.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\protected\stream_decoder.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\protected\stream_encoder.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\stream_encoder.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\stream_encoder_framing.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\window.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\all.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\assert.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\callback.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\export.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\format.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\metadata.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\ordinals.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\stream_decoder.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\stream_encoder.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\alloc.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\compat.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\endswap.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\macros.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\private.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\safe_str.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\windows_unicode_filenames.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="bitmath.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="bitreader.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="bitwriter.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="cpu.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="crc.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="fixed.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="fixed_intrin_sse2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="fixed_intrin_ssse3.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="float.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="format.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_sse.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_sse2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_sse41.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_avx2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="md5.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="memory.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_iterators.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_object.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ogg_decoder_aspect.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ogg_encoder_aspect.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ogg_helper.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ogg_mapping.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_decoder.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_framing.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_intrin_sse2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_intrin_ssse3.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_intrin_avx2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="window.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="windows_unicode_filenames.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="ia32\cpu_asm.nasm" />

+    <CustomBuild Include="ia32\fixed_asm.nasm" />

+    <CustomBuild Include="ia32\lpc_asm.nasm" />

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/libFLAC/libFLAC_static.vcproj b/src/libFLAC/libFLAC_static.vcproj
new file mode 100644
index 0000000..77ae97d
--- /dev/null
+++ b/src/libFLAC/libFLAC_static.vcproj
@@ -0,0 +1,533 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="libFLAC_static"

+	ProjectGUID="{4cefbc84-c215-11db-8314-0800200c9a66}"

+	RootNamespace="libFLAC_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				AdditionalOptions="/D &quot;_USE_MATH_DEFINES&quot;"

+				Optimization="0"

+				EnableIntrinsicFunctions="true"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION=\&quot;1.3.3\&quot;;FLAC__NO_DLL;DEBUG;FLAC__OVERFLOW_DETECT"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				AdditionalOptions="/D &quot;_USE_MATH_DEFINES&quot;"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION=\&quot;1.3.3\&quot;;FLAC__NO_DLL;FLaC__INLINE=_inline"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\include\private\all.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\protected\all.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\bitmath.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\bitreader.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\bitwriter.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\cpu.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\crc.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\fixed.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\float.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\format.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\lpc.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\md5.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\memory.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\metadata.h"

+				>

+			</File>

+			<File

+				RelativePath=".\ia32\nasm.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\ogg_decoder_aspect.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\ogg_encoder_aspect.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\ogg_helper.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\ogg_mapping.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\protected\stream_decoder.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\stream_encoder.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\protected\stream_encoder.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\stream_encoder_framing.h"

+				>

+			</File>

+			<File

+				RelativePath=".\include\private\window.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\include\FLAC\all.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\alloc.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\assert.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\callback.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\compat.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\endswap.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\export.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\format.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\macros.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\metadata.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\ordinals.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\private.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\safe_str.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\stream_decoder.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\FLAC\stream_encoder.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\share\windows_unicode_filenames.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\bitmath.c"

+				>

+			</File>

+			<File

+				RelativePath=".\bitreader.c"

+				>

+			</File>

+			<File

+				RelativePath=".\bitwriter.c"

+				>

+			</File>

+			<File

+				RelativePath=".\cpu.c"

+				>

+			</File>

+			<File

+				RelativePath=".\crc.c"

+				>

+			</File>

+			<File

+				RelativePath=".\fixed.c"

+				>

+			</File>

+			<File

+				RelativePath=".\fixed_intrin_sse2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\fixed_intrin_ssse3.c"

+				>

+			</File>

+			<File

+				RelativePath=".\float.c"

+				>

+			</File>

+			<File

+				RelativePath=".\format.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc_intrin_sse.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc_intrin_sse2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc_intrin_sse41.c"

+				>

+			</File>

+			<File

+				RelativePath=".\lpc_intrin_avx2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\md5.c"

+				>

+			</File>

+			<File

+				RelativePath=".\memory.c"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_iterators.c"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_object.c"

+				>

+			</File>

+			<File

+				RelativePath=".\ogg_decoder_aspect.c"

+				>

+			</File>

+			<File

+				RelativePath=".\ogg_encoder_aspect.c"

+				>

+			</File>

+			<File

+				RelativePath=".\ogg_helper.c"

+				>

+			</File>

+			<File

+				RelativePath=".\ogg_mapping.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_decoder.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder_framing.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder_intrin_sse2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder_intrin_ssse3.c"

+				>

+			</File>

+			<File

+				RelativePath=".\stream_encoder_intrin_avx2.c"

+				>

+			</File>

+			<File

+				RelativePath=".\window.c"

+				>

+			</File>

+			<File

+				RelativePath=".\windows_unicode_filenames.c"

+				>

+			</File>

+		</Filter>

+		<File

+			RelativePath=".\ia32\cpu_asm.nasm"

+			>

+			<FileConfiguration

+				Name="Debug|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/cpu_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/cpu_asm.obj"

+				/>

+			</FileConfiguration>

+			<FileConfiguration

+				Name="Release|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/cpu_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/cpu_asm.obj"

+				/>

+			</FileConfiguration>

+		</File>

+		<File

+			RelativePath=".\ia32\fixed_asm.nasm"

+			>

+			<FileConfiguration

+				Name="Debug|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/fixed_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/fixed_asm.obj"

+				/>

+			</FileConfiguration>

+			<FileConfiguration

+				Name="Release|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/fixed_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/fixed_asm.obj"

+				/>

+			</FileConfiguration>

+		</File>

+		<File

+			RelativePath=".\ia32\lpc_asm.nasm"

+			>

+			<FileConfiguration

+				Name="Debug|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/lpc_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/lpc_asm.obj"

+				/>

+			</FileConfiguration>

+			<FileConfiguration

+				Name="Release|Win32"

+				>

+				<Tool

+					Name="VCCustomBuildTool"

+					CommandLine="nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj&#x0D;&#x0A;"

+					AdditionalDependencies="ia32/lpc_asm.nasm;ia32/nasm.h"

+					Outputs="ia32/lpc_asm.obj"

+				/>

+			</FileConfiguration>

+		</File>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/libFLAC/libFLAC_static.vcxproj b/src/libFLAC/libFLAC_static.vcxproj
new file mode 100644
index 0000000..5e0443b
--- /dev/null
+++ b/src/libFLAC/libFLAC_static.vcxproj
@@ -0,0 +1,287 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc84-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>libFLAC_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <AdditionalOptions>/D "_USE_MATH_DEFINES" %(AdditionalOptions)</AdditionalOptions>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION="1.3.3";FLAC__NO_DLL;DEBUG;FLAC__OVERFLOW_DETECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <AdditionalOptions>/D "_USE_MATH_DEFINES" %(AdditionalOptions)</AdditionalOptions>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__HAS_OGG;ENABLE_64_BIT_WORDS;FLAC__CPU_X86_64;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION="1.3.3";FLAC__NO_DLL;DEBUG;FLAC__OVERFLOW_DETECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <AdditionalOptions>/D "_USE_MATH_DEFINES" %(AdditionalOptions)</AdditionalOptions>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION="1.3.3";FLAC__NO_DLL;FLaC__INLINE=_inline;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+      <FloatingPointModel>Fast</FloatingPointModel>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <AdditionalOptions>/D "_USE_MATH_DEFINES" %(AdditionalOptions)</AdditionalOptions>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__HAS_OGG;ENABLE_64_BIT_WORDS;FLAC__CPU_X86_64;FLAC__HAS_X86INTRIN;FLAC__ALIGN_MALLOC_DATA;PACKAGE_VERSION="1.3.3";FLAC__NO_DLL;FLaC__INLINE=_inline;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+      <FloatingPointModel>Fast</FloatingPointModel>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\include\FLAC\all.h" />

+    <ClInclude Include="..\..\include\FLAC\assert.h" />

+    <ClInclude Include="..\..\include\FLAC\callback.h" />

+    <ClInclude Include="..\..\include\FLAC\export.h" />

+    <ClInclude Include="..\..\include\FLAC\format.h" />

+    <ClInclude Include="..\..\include\FLAC\metadata.h" />

+    <ClInclude Include="..\..\include\FLAC\ordinals.h" />

+    <ClInclude Include="..\..\include\FLAC\stream_decoder.h" />

+    <ClInclude Include="..\..\include\FLAC\stream_encoder.h" />

+    <ClInclude Include="..\..\include\share\alloc.h" />

+    <ClInclude Include="..\..\include\share\compat.h" />

+    <ClInclude Include="..\..\include\share\endswap.h" />

+    <ClInclude Include="..\..\include\share\macros.h" />

+    <ClInclude Include="..\..\include\share\private.h" />

+    <ClInclude Include="..\..\include\share\safe_str.h" />

+    <ClInclude Include="..\..\include\share\windows_unicode_filenames.h" />

+    <ClInclude Include="ia32\nasm.h" />

+    <ClInclude Include="include\private\all.h" />

+    <ClInclude Include="include\private\bitmath.h" />

+    <ClInclude Include="include\private\bitreader.h" />

+    <ClInclude Include="include\private\bitwriter.h" />

+    <ClInclude Include="include\private\cpu.h" />

+    <ClInclude Include="include\private\crc.h" />

+    <ClInclude Include="include\private\fixed.h" />

+    <ClInclude Include="include\private\float.h" />

+    <ClInclude Include="include\private\format.h" />

+    <ClInclude Include="include\private\lpc.h" />

+    <ClInclude Include="include\private\md5.h" />

+    <ClInclude Include="include\private\memory.h" />

+    <ClInclude Include="include\private\metadata.h" />

+    <ClInclude Include="include\private\ogg_decoder_aspect.h" />

+    <ClInclude Include="include\private\ogg_encoder_aspect.h" />

+    <ClInclude Include="include\private\ogg_helper.h" />

+    <ClInclude Include="include\private\ogg_mapping.h" />

+    <ClInclude Include="include\private\stream_encoder.h" />

+    <ClInclude Include="include\private\stream_encoder_framing.h" />

+    <ClInclude Include="include\private\window.h" />

+    <ClInclude Include="include\protected\all.h" />

+    <ClInclude Include="include\protected\stream_decoder.h" />

+    <ClInclude Include="include\protected\stream_encoder.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="bitmath.c" />

+    <ClCompile Include="bitreader.c" />

+    <ClCompile Include="bitwriter.c" />

+    <ClCompile Include="cpu.c" />

+    <ClCompile Include="crc.c" />

+    <ClCompile Include="fixed.c" />

+    <ClCompile Include="fixed_intrin_sse2.c" />

+    <ClCompile Include="fixed_intrin_ssse3.c" />

+    <ClCompile Include="float.c" />

+    <ClCompile Include="format.c" />

+    <ClCompile Include="lpc.c" />

+    <ClCompile Include="lpc_intrin_avx2.c">

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_sse.c" />

+    <ClCompile Include="lpc_intrin_sse2.c" />

+    <ClCompile Include="lpc_intrin_sse41.c" />

+    <ClCompile Include="md5.c" />

+    <ClCompile Include="memory.c" />

+    <ClCompile Include="metadata_iterators.c" />

+    <ClCompile Include="metadata_object.c" />

+    <ClCompile Include="ogg_decoder_aspect.c" />

+    <ClCompile Include="ogg_encoder_aspect.c" />

+    <ClCompile Include="ogg_helper.c" />

+    <ClCompile Include="ogg_mapping.c" />

+    <ClCompile Include="stream_decoder.c" />

+    <ClCompile Include="stream_encoder.c" />

+    <ClCompile Include="stream_encoder_framing.c" />

+    <ClCompile Include="stream_encoder_intrin_avx2.c">

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">/arch:AVX %(AdditionalOptions)</AdditionalOptions>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_intrin_sse2.c" />

+    <ClCompile Include="stream_encoder_intrin_ssse3.c" />

+    <ClCompile Include="window.c" />

+    <ClCompile Include="windows_unicode_filenames.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="ia32\cpu_asm.nasm">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/cpu_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/cpu_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/cpu_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/cpu_asm.obj;%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/cpu_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/cpu_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/cpu_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/cpu_asm.obj;%(Outputs)</Outputs>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

+    </CustomBuild>

+    <CustomBuild Include="ia32\fixed_asm.nasm">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/fixed_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/fixed_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/fixed_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/fixed_asm.obj;%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/fixed_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/fixed_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/fixed_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/fixed_asm.obj;%(Outputs)</Outputs>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

+    </CustomBuild>

+    <CustomBuild Include="ia32\lpc_asm.nasm">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/lpc_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/lpc_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ia32/lpc_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ia32/lpc_asm.obj;%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj

+</Command>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nasm.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj

+</Command>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/lpc_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/lpc_asm.nasm;ia32/nasm.h;%(AdditionalInputs)</AdditionalInputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ia32/lpc_asm.obj;%(Outputs)</Outputs>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ia32/lpc_asm.obj;%(Outputs)</Outputs>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

+    </CustomBuild>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/libFLAC/libFLAC_static.vcxproj.filters b/src/libFLAC/libFLAC_static.vcxproj.filters
new file mode 100644
index 0000000..a600678
--- /dev/null
+++ b/src/libFLAC/libFLAC_static.vcxproj.filters
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{7493d9cf-1406-4a3c-9811-63f0cd6ccd36}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="include\protected\all.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\all.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\bitmath.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\bitreader.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\bitwriter.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\cpu.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\crc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\fixed.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\float.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\format.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\lpc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\md5.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\memory.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\metadata.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ia32\nasm.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\ogg_decoder_aspect.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\ogg_encoder_aspect.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\ogg_helper.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\ogg_mapping.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\protected\stream_decoder.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\protected\stream_encoder.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\stream_encoder.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\stream_encoder_framing.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="include\private\window.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\all.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\assert.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\callback.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\export.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\format.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\metadata.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\ordinals.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\stream_decoder.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\FLAC\stream_encoder.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\alloc.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\compat.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\endswap.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\macros.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\private.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\safe_str.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\include\share\windows_unicode_filenames.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="bitmath.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="bitreader.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="bitwriter.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="cpu.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="crc.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="fixed.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="fixed_intrin_sse2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="fixed_intrin_ssse3.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="float.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="format.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_sse.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_sse2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_sse41.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="lpc_intrin_avx2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="md5.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="memory.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_iterators.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_object.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ogg_decoder_aspect.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ogg_encoder_aspect.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ogg_helper.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ogg_mapping.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_decoder.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_framing.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_intrin_sse2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_intrin_ssse3.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="stream_encoder_intrin_avx2.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="window.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="windows_unicode_filenames.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="ia32\cpu_asm.nasm" />

+    <CustomBuild Include="ia32\fixed_asm.nasm" />

+    <CustomBuild Include="ia32\lpc_asm.nasm" />

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/libFLAC/lpc.c b/src/libFLAC/lpc.c
new file mode 100644
index 0000000..9b80036
--- /dev/null
+++ b/src/libFLAC/lpc.c
@@ -0,0 +1,1357 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 "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(NDEBUG) || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE
+#include <stdio.h>
+#endif
+
+/* OPT: #undef'ing this may improve the speed on some architectures */
+#define FLAC__LPC_UNROLLED_FILTER_LOOPS
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#if defined(_MSC_VER) && (_MSC_VER < 1800)
+#include <float.h>
+static inline long int lround(double x) {
+	return (long)(x + _copysign(0.5, x));
+}
+#elif !defined(HAVE_LROUND) && defined(__GNUC__)
+static inline long int lround(double x) {
+	return (long)(x + __builtin_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[], uint32_t data_len)
+{
+	uint32_t i;
+	for(i = 0; i < data_len; i++)
+		out[i] = in[i] * window[i];
+}
+
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	/* a readable, but slower, version */
+#if 0
+	FLAC__real d;
+	uint32_t i;
+
+	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];
+		autoc[lag] = d;
+	}
+#endif
+
+	/*
+	 * this version tends to run faster because of better data locality
+	 * ('data_len' is usually much larger than 'lag')
+	 */
+	FLAC__real d;
+	uint32_t sample, coeff;
+	const uint32_t limit = data_len - lag;
+
+	FLAC__ASSERT(lag > 0);
+	FLAC__ASSERT(lag <= data_len);
+
+	for(coeff = 0; coeff < lag; coeff++)
+		autoc[coeff] = 0.0;
+	for(sample = 0; sample <= limit; sample++) {
+		d = data[sample];
+		for(coeff = 0; coeff < lag; coeff++)
+			autoc[coeff] += d * data[sample+coeff];
+	}
+	for(; sample < data_len; sample++) {
+		d = data[sample];
+		for(coeff = 0; coeff < data_len - sample; coeff++)
+			autoc[coeff] += d * data[sample+coeff];
+	}
+}
+
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[])
+{
+	uint32_t i, j;
+	double r, err, lpc[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++) {
+		/* Sum up this iteration's reflection coefficient. */
+		r = -autoc[i+1];
+		for(j = 0; j < i; j++)
+			r -= lpc[j] * autoc[i-j];
+		r /= err;
+
+		/* Update LPC coefficients and total error. */
+		lpc[i]=r;
+		for(j = 0; j < (i>>1); j++) {
+			double tmp = lpc[j];
+			lpc[j] += r * lpc[i-1-j];
+			lpc[i-1-j] += r * tmp;
+		}
+		if(i & 1)
+			lpc[j] += lpc[j] * r;
+
+		err *= (1.0 - r * r);
+
+		/* save this order */
+		for(j = 0; j <= i; j++)
+			lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
+		error[i] = err;
+
+		/* see SF bug https://sourceforge.net/p/flac/bugs/234/ */
+		if(err == 0.0) {
+			*max_order = i+1;
+			return;
+		}
+	}
+}
+
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift)
+{
+	uint32_t i;
+	double cmax;
+	FLAC__int32 qmax, qmin;
+
+	FLAC__ASSERT(precision > 0);
+	FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
+
+	/* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
+	precision--;
+	qmax = 1 << precision;
+	qmin = -qmax;
+	qmax--;
+
+	/* calc cmax = max( |lp_coeff[i]| ) */
+	cmax = 0.0;
+	for(i = 0; i < order; i++) {
+		const double d = fabs(lp_coeff[i]);
+		if(d > cmax)
+			cmax = d;
+	}
+
+	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);
+		log2cmax--;
+		*shift = (int)precision - log2cmax - 1;
+
+		if(*shift > max_shiftlimit)
+			*shift = max_shiftlimit;
+		else if(*shift < min_shiftlimit)
+			return 1;
+	}
+
+	if(*shift >= 0) {
+		double error = 0.0;
+		FLAC__int32 q;
+		for(i = 0; i < order; i++) {
+			error += lp_coeff[i] * (1 << *shift);
+			q = lround(error);
+
+#ifdef FLAC__OVERFLOW_DETECT
+			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
+			if(q > qmax)
+				q = qmax;
+			else if(q < qmin)
+				q = qmin;
+			error -= q;
+			qlp_coeff[i] = q;
+		}
+	}
+	/* negative shift is very rare but due to design flaw, negative shift is
+	 * not allowed in the decoder, so it must be handled specially by scaling
+	 * down coeffs
+	 */
+	else {
+		const int nshift = -(*shift);
+		double error = 0.0;
+		FLAC__int32 q;
+#ifndef NDEBUG
+		fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax);
+#endif
+		for(i = 0; i < order; i++) {
+			error += lp_coeff[i] / (1 << nshift);
+			q = lround(error);
+#ifdef FLAC__OVERFLOW_DETECT
+			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
+			if(q > qmax)
+				q = qmax;
+			else if(q < qmin)
+				q = qmin;
+			error -= q;
+			qlp_coeff[i] = q;
+		}
+		*shift = 0;
+	}
+
+	return 0;
+}
+
+#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, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+	FLAC__int64 sumo;
+	uint32_t i, j;
+	FLAC__int32 sum;
+	const FLAC__int32 *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+	fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+	for(i=0;i<order;i++)
+		fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+	fprintf(stderr,"\n");
+#endif
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sumo = 0;
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++) {
+			sum += qlp_coeff[j] * (*(--history));
+			sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+			if(sumo > 2147483647ll || sumo < -2147483648ll)
+				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);
+	}
+
+	/* Here's a slower but clearer version:
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		for(j = 0; j < order; j++)
+			sum += qlp_coeff[j] * data[i-j-1];
+		residual[i] = data[i] - (sum >> lp_quantization);
+	}
+	*/
+}
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int32 sum;
+
+	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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				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, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+	uint32_t i, j;
+	FLAC__int64 sum;
+	const FLAC__int32 *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+	fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+	for(i=0;i<order;i++)
+		fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+	fprintf(stderr,"\n");
+#endif
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++)
+			sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+		if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) {
+			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((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
+			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;
+		}
+		*(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
+	}
+}
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int64 sum;
+
+	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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+				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, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+	FLAC__int64 sumo;
+	uint32_t i, j;
+	FLAC__int32 sum;
+	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);
+	for(i=0;i<order;i++)
+		fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+	fprintf(stderr,"\n");
+#endif
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sumo = 0;
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++) {
+			sum += qlp_coeff[j] * (*(--history));
+			sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+			if(sumo > 2147483647ll || sumo < -2147483648ll)
+				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++) = *(r++) + (sum >> lp_quantization);
+	}
+
+	/* Here's a slower but clearer version:
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		for(j = 0; j < order; j++)
+			sum += qlp_coeff[j] * data[i-j-1];
+		data[i] = residual[i] + (sum >> lp_quantization);
+	}
+	*/
+}
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int32 sum;
+
+	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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				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, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+	uint32_t i, j;
+	FLAC__int64 sum;
+	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);
+	for(i=0;i<order;i++)
+		fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+	fprintf(stderr,"\n");
+#endif
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++)
+			sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+		if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) {
+			fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization));
+			break;
+		}
+		if(FLAC__bitmath_silog2((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;
+		}
+		*(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization);
+	}
+}
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int64 sum;
+
+	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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (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] * (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (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] * (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+				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] = (FLAC__int32) (residual[i] + (sum >> lp_quantization));
+		}
+	}
+}
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4028 )
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples)
+{
+	double error_scale;
+
+	FLAC__ASSERT(total_samples > 0);
+
+	error_scale = 0.5 / (double)total_samples;
+
+	return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
+}
+
+double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale)
+{
+	if(lpc_error > 0.0) {
+		double bps = (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 floating-point resolution */
+		return 1e32;
+	}
+	else {
+		return 0.0;
+	}
+}
+
+uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order)
+{
+	uint32_t 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 */
+	double bits, best_bits, error_scale;
+
+	FLAC__ASSERT(max_order > 0);
+	FLAC__ASSERT(total_samples > 0);
+
+	error_scale = 0.5 / (double)total_samples;
+
+	best_index = 0;
+	best_bits = (uint32_t)(-1);
+
+	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) * (double)(total_samples - order) + (double)(order * overhead_bits_per_order);
+		if(bits < best_bits) {
+			best_index = indx;
+			best_bits = bits;
+		}
+	}
+
+	return best_index+1; /* +1 since indx of lpc_error[] is order-1 */
+}
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_avx2.c b/src/libFLAC/lpc_intrin_avx2.c
new file mode 100644
index 0000000..8a0a94b
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_avx2.c
@@ -0,0 +1,1122 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/lpc.h"
+#ifdef FLAC__AVX2_SUPPORTED
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+
+#include <immintrin.h> /* AVX2 */
+
+FLAC__SSE_TARGET("avx2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+	int i;
+	FLAC__int32 sum;
+	const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+					q8  = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
+					q9  = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
+					q10 = _mm256_set1_epi32(0xffff & qlp_coeff[10]);
+					q11 = _mm256_set1_epi32(0xffff & qlp_coeff[11]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q11, _mm256_loadu_si256((const __m256i*)(data+i-12)));
+						mull = _mm256_madd_epi16(q10, _mm256_loadu_si256((const __m256i*)(data+i-11))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 11 */
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+					q8  = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
+					q9  = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
+					q10 = _mm256_set1_epi32(0xffff & qlp_coeff[10]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q10, _mm256_loadu_si256((const __m256i*)(data+i-11)));
+						mull = _mm256_madd_epi16(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+					q8  = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
+					q9  = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10)));
+						mull = _mm256_madd_epi16(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 9 */
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+					q8  = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9 )));
+						mull = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8 )));
+						mull = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 7 */
+					__m256i q0, q1, q2, q3, q4, q5, q6;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7 )));
+						mull = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					__m256i q0, q1, q2, q3, q4, q5;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6 )));
+						mull = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 5 */
+					__m256i q0, q1, q2, q3, q4;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5 )));
+						mull = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					__m256i q0, q1, q2, q3;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4 )));
+						mull = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 3 */
+					__m256i q0, q1, q2;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3 )));
+						mull = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					__m256i q0, q1;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_madd_epi16(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2 )));
+						mull = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 1 */
+					__m256i q0;
+					q0  = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ;
+						summ = _mm256_madd_epi16(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1 )));
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		for(; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+				case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+				case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+				case 9:  sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+				case 8:  sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+				case 7:  sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+				case 6:  sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+				case 5:  sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+				case 4:  sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+				case 3:  sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+				case 2:  sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+				case 1:  sum += qlp_coeff[ 0] * data[i- 1];
+			}
+			residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				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);
+		}
+	}
+	_mm256_zeroupper();
+}
+
+FLAC__SSE_TARGET("avx2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+	int i;
+	FLAC__int32 sum;
+	const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
+					q8  = _mm256_set1_epi32(qlp_coeff[8 ]);
+					q9  = _mm256_set1_epi32(qlp_coeff[9 ]);
+					q10 = _mm256_set1_epi32(qlp_coeff[10]);
+					q11 = _mm256_set1_epi32(qlp_coeff[11]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q11, _mm256_loadu_si256((const __m256i*)(data+i-12)));
+						mull = _mm256_mullo_epi32(q10, _mm256_loadu_si256((const __m256i*)(data+i-11))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 11 */
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
+					q8  = _mm256_set1_epi32(qlp_coeff[8 ]);
+					q9  = _mm256_set1_epi32(qlp_coeff[9 ]);
+					q10 = _mm256_set1_epi32(qlp_coeff[10]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q10, _mm256_loadu_si256((const __m256i*)(data+i-11)));
+						mull = _mm256_mullo_epi32(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
+					q8  = _mm256_set1_epi32(qlp_coeff[8 ]);
+					q9  = _mm256_set1_epi32(qlp_coeff[9 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q9,  _mm256_loadu_si256((const __m256i*)(data+i-10)));
+						mull = _mm256_mullo_epi32(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 9 */
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
+					q8  = _mm256_set1_epi32(qlp_coeff[8 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q8,  _mm256_loadu_si256((const __m256i*)(data+i-9)));
+						mull = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
+					q7  = _mm256_set1_epi32(qlp_coeff[7 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q7,  _mm256_loadu_si256((const __m256i*)(data+i-8)));
+						mull = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 7 */
+					__m256i q0, q1, q2, q3, q4, q5, q6;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
+					q6  = _mm256_set1_epi32(qlp_coeff[6 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q6,  _mm256_loadu_si256((const __m256i*)(data+i-7)));
+						mull = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					__m256i q0, q1, q2, q3, q4, q5;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
+					q5  = _mm256_set1_epi32(qlp_coeff[5 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q5,  _mm256_loadu_si256((const __m256i*)(data+i-6)));
+						mull = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 5 */
+					__m256i q0, q1, q2, q3, q4;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+					q4  = _mm256_set1_epi32(qlp_coeff[4 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q4,  _mm256_loadu_si256((const __m256i*)(data+i-5)));
+						mull = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					__m256i q0, q1, q2, q3;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+					q3  = _mm256_set1_epi32(qlp_coeff[3 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q3,  _mm256_loadu_si256((const __m256i*)(data+i-4)));
+						mull = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 3 */
+					__m256i q0, q1, q2;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+					q2  = _mm256_set1_epi32(qlp_coeff[2 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q2,  _mm256_loadu_si256((const __m256i*)(data+i-3)));
+						mull = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));  summ = _mm256_add_epi32(summ, mull);
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					__m256i q0, q1;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+					q1  = _mm256_set1_epi32(qlp_coeff[1 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ, mull;
+						summ = _mm256_mullo_epi32(q1,  _mm256_loadu_si256((const __m256i*)(data+i-2)));
+						mull = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));  summ = _mm256_add_epi32(summ, mull);
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 1 */
+					__m256i q0;
+					q0  = _mm256_set1_epi32(qlp_coeff[0 ]);
+
+					for(i = 0; i < (int)data_len-7; i+=8) {
+						__m256i summ;
+						summ = _mm256_mullo_epi32(q0,  _mm256_loadu_si256((const __m256i*)(data+i-1)));
+						summ = _mm256_sra_epi32(summ, cnt);
+						_mm256_storeu_si256((__m256i*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		for(; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+				case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+				case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+				case 9:  sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+				case 8:  sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+				case 7:  sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+				case 6:  sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+				case 5:  sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+				case 4:  sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+				case 3:  sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+				case 2:  sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+				case 1:  sum += qlp_coeff[ 0] * data[i- 1];
+			}
+			residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				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);
+		}
+	}
+	_mm256_zeroupper();
+}
+
+static FLAC__int32 pack_arr[8] = { 0, 2, 4, 6, 1, 3, 5, 7 };
+
+FLAC__SSE_TARGET("avx2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+	int i;
+	FLAC__int64 sum;
+	const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+	const __m256i pack = _mm256_loadu_si256((const __m256i *)pack_arr);
+
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+	FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm256_sra_epi64() so we have to use _mm256_srl_epi64() */
+
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+					q8  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
+					q9  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
+					q10 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[10]));
+					q11 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[11]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q11, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-12))));
+						mull = _mm256_mul_epi32(q10, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-11)))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q9,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-10)))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q8,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+				else { /* order == 11 */
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+					q8  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
+					q9  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
+					q10 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[10]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q10, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-11))));
+						mull = _mm256_mul_epi32(q9,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-10)))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q8,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+					q8  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
+					q9  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q9,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-10))));
+						mull = _mm256_mul_epi32(q8,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+				else { /* order == 9 */
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+					q8  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q8,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-9 ))));
+						mull = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					__m256i q0, q1, q2, q3, q4, q5, q6, q7;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+					q7  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q7,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-8 ))));
+						mull = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+				else { /* order == 7 */
+					__m256i q0, q1, q2, q3, q4, q5, q6;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+					q6  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q6,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-7 ))));
+						mull = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					__m256i q0, q1, q2, q3, q4, q5;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+					q5  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q5,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-6 ))));
+						mull = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+				else { /* order == 5 */
+					__m256i q0, q1, q2, q3, q4;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+					q4  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q4,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-5 ))));
+						mull = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					__m256i q0, q1, q2, q3;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+					q3  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q3,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-4 ))));
+						mull = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+				else { /* order == 3 */
+					__m256i q0, q1, q2;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+					q2  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q2,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-3 ))));
+						mull = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					__m256i q0, q1;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+					q1  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ, mull;
+						summ = _mm256_mul_epi32(q1,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-2 ))));
+						mull = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+				else { /* order == 1 */
+					__m256i q0;
+					q0  = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m256i summ;
+						summ = _mm256_mul_epi32(q0,  _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(data+i-1 ))));
+						summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), _mm256_castsi256_si128(summ)));
+					}
+				}
+			}
+		}
+		for(; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 12: sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; /* Falls through. */
+				case 11: sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; /* Falls through. */
+				case 10: sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; /* Falls through. */
+				case 9:  sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; /* Falls through. */
+				case 8:  sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; /* Falls through. */
+				case 7:  sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; /* Falls through. */
+				case 6:  sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; /* Falls through. */
+				case 5:  sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; /* Falls through. */
+				case 4:  sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; /* Falls through. */
+				case 3:  sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; /* Falls through. */
+				case 2:  sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; /* Falls through. */
+				case 1:  sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+			}
+			residual[i] = data[i] - (FLAC__int32)(sum >> 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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+				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);
+		}
+	}
+	_mm256_zeroupper();
+}
+
+#endif /* FLAC__AVX2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_sse.c b/src/libFLAC/lpc_intrin_sse.c
new file mode 100644
index 0000000..8c7902f
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_sse.c
@@ -0,0 +1,454 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/lpc.h"
+#ifdef FLAC__SSE_SUPPORTED
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+
+#include <xmmintrin.h> /* SSE */
+
+/*   new routines: more unaligned loads, less shuffle
+ *   old routines: less unaligned loads, more shuffle
+ *   these *_old routines are equivalent to the ASM routines in ia32/lpc_asm.nasm
+ */
+
+/* new routines: faster on current Intel (starting from Core i aka Nehalem) and all AMD CPUs */
+
+FLAC__SSE_TARGET("sse")
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	int i;
+	int limit = data_len - 4;
+	__m128 sum0;
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 4);
+	FLAC__ASSERT(lag <= data_len);
+
+	sum0 = _mm_setzero_ps();
+
+	for(i = 0; i <= limit; i++) {
+		__m128 d, d0;
+		d0 = _mm_loadu_ps(data+i);
+		d = _mm_shuffle_ps(d0, d0, 0);
+		sum0 = _mm_add_ps(sum0, _mm_mul_ps(d0, d));
+	}
+
+	{
+		__m128 d0 = _mm_setzero_ps();
+		limit++; if(limit < 0) limit = 0;
+
+		for(i = data_len-1; i >= limit; i--) {
+			__m128 d;
+			d = _mm_load_ss(data+i); d = _mm_shuffle_ps(d, d, 0);
+			d0 = _mm_shuffle_ps(d0, d0, _MM_SHUFFLE(2,1,0,3));
+			d0 = _mm_move_ss(d0, d);
+			sum0 = _mm_add_ps(sum0, _mm_mul_ps(d, d0));
+		}
+	}
+
+	_mm_storeu_ps(autoc,   sum0);
+}
+
+FLAC__SSE_TARGET("sse")
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	int i;
+	int limit = data_len - 8;
+	__m128 sum0, sum1;
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 8);
+	FLAC__ASSERT(lag <= data_len);
+
+	sum0 = _mm_setzero_ps();
+	sum1 = _mm_setzero_ps();
+
+	for(i = 0; i <= limit; i++) {
+		__m128 d, d0, d1;
+		d0 = _mm_loadu_ps(data+i);
+		d1 = _mm_loadu_ps(data+i+4);
+		d = _mm_shuffle_ps(d0, d0, 0);
+		sum0 = _mm_add_ps(sum0, _mm_mul_ps(d0, d));
+		sum1 = _mm_add_ps(sum1, _mm_mul_ps(d1, d));
+	}
+
+	{
+		__m128 d0 = _mm_setzero_ps();
+		__m128 d1 = _mm_setzero_ps();
+		limit++; if(limit < 0) limit = 0;
+
+		for(i = data_len-1; i >= limit; i--) {
+			__m128 d;
+			d = _mm_load_ss(data+i); d = _mm_shuffle_ps(d, d, 0);
+			d1 = _mm_shuffle_ps(d1, d1, _MM_SHUFFLE(2,1,0,3));
+			d0 = _mm_shuffle_ps(d0, d0, _MM_SHUFFLE(2,1,0,3));
+			d1 = _mm_move_ss(d1, d0);
+			d0 = _mm_move_ss(d0, d);
+			sum1 = _mm_add_ps(sum1, _mm_mul_ps(d, d1));
+			sum0 = _mm_add_ps(sum0, _mm_mul_ps(d, d0));
+		}
+	}
+
+	_mm_storeu_ps(autoc,   sum0);
+	_mm_storeu_ps(autoc+4, sum1);
+}
+
+FLAC__SSE_TARGET("sse")
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	int i;
+	int limit = data_len - 12;
+	__m128 sum0, sum1, sum2;
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 12);
+	FLAC__ASSERT(lag <= data_len);
+
+	sum0 = _mm_setzero_ps();
+	sum1 = _mm_setzero_ps();
+	sum2 = _mm_setzero_ps();
+
+	for(i = 0; i <= limit; i++) {
+		__m128 d, d0, d1, d2;
+		d0 = _mm_loadu_ps(data+i);
+		d1 = _mm_loadu_ps(data+i+4);
+		d2 = _mm_loadu_ps(data+i+8);
+		d = _mm_shuffle_ps(d0, d0, 0);
+		sum0 = _mm_add_ps(sum0, _mm_mul_ps(d0, d));
+		sum1 = _mm_add_ps(sum1, _mm_mul_ps(d1, d));
+		sum2 = _mm_add_ps(sum2, _mm_mul_ps(d2, d));
+	}
+
+	{
+		__m128 d0 = _mm_setzero_ps();
+		__m128 d1 = _mm_setzero_ps();
+		__m128 d2 = _mm_setzero_ps();
+		limit++; if(limit < 0) limit = 0;
+
+		for(i = data_len-1; i >= limit; i--) {
+			__m128 d;
+			d = _mm_load_ss(data+i); d = _mm_shuffle_ps(d, d, 0);
+			d2 = _mm_shuffle_ps(d2, d2, _MM_SHUFFLE(2,1,0,3));
+			d1 = _mm_shuffle_ps(d1, d1, _MM_SHUFFLE(2,1,0,3));
+			d0 = _mm_shuffle_ps(d0, d0, _MM_SHUFFLE(2,1,0,3));
+			d2 = _mm_move_ss(d2, d1);
+			d1 = _mm_move_ss(d1, d0);
+			d0 = _mm_move_ss(d0, d);
+			sum2 = _mm_add_ps(sum2, _mm_mul_ps(d, d2));
+			sum1 = _mm_add_ps(sum1, _mm_mul_ps(d, d1));
+			sum0 = _mm_add_ps(sum0, _mm_mul_ps(d, d0));
+		}
+	}
+
+	_mm_storeu_ps(autoc,   sum0);
+	_mm_storeu_ps(autoc+4, sum1);
+	_mm_storeu_ps(autoc+8, sum2);
+}
+
+FLAC__SSE_TARGET("sse")
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	int i;
+	int limit = data_len - 16;
+	__m128 sum0, sum1, sum2, sum3;
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 16);
+	FLAC__ASSERT(lag <= data_len);
+
+	sum0 = _mm_setzero_ps();
+	sum1 = _mm_setzero_ps();
+	sum2 = _mm_setzero_ps();
+	sum3 = _mm_setzero_ps();
+
+	for(i = 0; i <= limit; i++) {
+		__m128 d, d0, d1, d2, d3;
+		d0 = _mm_loadu_ps(data+i);
+		d1 = _mm_loadu_ps(data+i+4);
+		d2 = _mm_loadu_ps(data+i+8);
+		d3 = _mm_loadu_ps(data+i+12);
+		d = _mm_shuffle_ps(d0, d0, 0);
+		sum0 = _mm_add_ps(sum0, _mm_mul_ps(d0, d));
+		sum1 = _mm_add_ps(sum1, _mm_mul_ps(d1, d));
+		sum2 = _mm_add_ps(sum2, _mm_mul_ps(d2, d));
+		sum3 = _mm_add_ps(sum3, _mm_mul_ps(d3, d));
+	}
+
+	{
+		__m128 d0 = _mm_setzero_ps();
+		__m128 d1 = _mm_setzero_ps();
+		__m128 d2 = _mm_setzero_ps();
+		__m128 d3 = _mm_setzero_ps();
+		limit++; if(limit < 0) limit = 0;
+
+		for(i = data_len-1; i >= limit; i--) {
+			__m128 d;
+			d = _mm_load_ss(data+i); d = _mm_shuffle_ps(d, d, 0);
+			d3 = _mm_shuffle_ps(d3, d3, _MM_SHUFFLE(2,1,0,3));
+			d2 = _mm_shuffle_ps(d2, d2, _MM_SHUFFLE(2,1,0,3));
+			d1 = _mm_shuffle_ps(d1, d1, _MM_SHUFFLE(2,1,0,3));
+			d0 = _mm_shuffle_ps(d0, d0, _MM_SHUFFLE(2,1,0,3));
+			d3 = _mm_move_ss(d3, d2);
+			d2 = _mm_move_ss(d2, d1);
+			d1 = _mm_move_ss(d1, d0);
+			d0 = _mm_move_ss(d0, d);
+			sum3 = _mm_add_ps(sum3, _mm_mul_ps(d, d3));
+			sum2 = _mm_add_ps(sum2, _mm_mul_ps(d, d2));
+			sum1 = _mm_add_ps(sum1, _mm_mul_ps(d, d1));
+			sum0 = _mm_add_ps(sum0, _mm_mul_ps(d, d0));
+		}
+	}
+
+	_mm_storeu_ps(autoc,   sum0);
+	_mm_storeu_ps(autoc+4, sum1);
+	_mm_storeu_ps(autoc+8, sum2);
+	_mm_storeu_ps(autoc+12,sum3);
+}
+
+/* old routines: faster on older Intel CPUs (up to Core 2) */
+
+FLAC__SSE_TARGET("sse")
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	__m128 xmm0, xmm2, xmm5;
+
+	(void) lag;
+	FLAC__ASSERT(lag > 0);
+	FLAC__ASSERT(lag <= 4);
+	FLAC__ASSERT(lag <= data_len);
+	FLAC__ASSERT(data_len > 0);
+
+	xmm5 = _mm_setzero_ps();
+
+	xmm0 = _mm_load_ss(data++);
+	xmm2 = xmm0;
+	xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0);
+
+	xmm0 = _mm_mul_ps(xmm0, xmm2);
+	xmm5 = _mm_add_ps(xmm5, xmm0);
+
+	data_len--;
+
+	while(data_len)
+	{
+		xmm0 = _mm_load1_ps(data++);
+
+		xmm2 = _mm_shuffle_ps(xmm2, xmm2, _MM_SHUFFLE(2,1,0,3));
+		xmm2 = _mm_move_ss(xmm2, xmm0);
+		xmm0 = _mm_mul_ps(xmm0, xmm2);
+		xmm5 = _mm_add_ps(xmm5, xmm0);
+
+		data_len--;
+	}
+
+	_mm_storeu_ps(autoc, xmm5);
+}
+
+FLAC__SSE_TARGET("sse")
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	__m128 xmm0, xmm1, xmm2, xmm3, xmm5, xmm6;
+
+	(void) lag;
+	FLAC__ASSERT(lag > 0);
+	FLAC__ASSERT(lag <= 8);
+	FLAC__ASSERT(lag <= data_len);
+	FLAC__ASSERT(data_len > 0);
+
+	xmm5 = _mm_setzero_ps();
+	xmm6 = _mm_setzero_ps();
+
+	xmm0 = _mm_load_ss(data++);
+	xmm2 = xmm0;
+	xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0);
+	xmm3 = _mm_setzero_ps();
+
+	xmm0 = _mm_mul_ps(xmm0, xmm2);
+	xmm5 = _mm_add_ps(xmm5, xmm0);
+
+	data_len--;
+
+	while(data_len)
+	{
+		xmm0 = _mm_load1_ps(data++);
+
+		xmm2 = _mm_shuffle_ps(xmm2, xmm2, _MM_SHUFFLE(2,1,0,3));
+		xmm3 = _mm_shuffle_ps(xmm3, xmm3, _MM_SHUFFLE(2,1,0,3));
+		xmm3 = _mm_move_ss(xmm3, xmm2);
+		xmm2 = _mm_move_ss(xmm2, xmm0);
+
+		xmm1 = xmm0;
+		xmm1 = _mm_mul_ps(xmm1, xmm3);
+		xmm0 = _mm_mul_ps(xmm0, xmm2);
+		xmm6 = _mm_add_ps(xmm6, xmm1);
+		xmm5 = _mm_add_ps(xmm5, xmm0);
+
+		data_len--;
+	}
+
+	_mm_storeu_ps(autoc,   xmm5);
+	_mm_storeu_ps(autoc+4, xmm6);
+}
+
+FLAC__SSE_TARGET("sse")
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	__m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+
+	(void) lag;
+	FLAC__ASSERT(lag > 0);
+	FLAC__ASSERT(lag <= 12);
+	FLAC__ASSERT(lag <= data_len);
+	FLAC__ASSERT(data_len > 0);
+
+	xmm5 = _mm_setzero_ps();
+	xmm6 = _mm_setzero_ps();
+	xmm7 = _mm_setzero_ps();
+
+	xmm0 = _mm_load_ss(data++);
+	xmm2 = xmm0;
+	xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0);
+	xmm3 = _mm_setzero_ps();
+	xmm4 = _mm_setzero_ps();
+
+	xmm0 = _mm_mul_ps(xmm0, xmm2);
+	xmm5 = _mm_add_ps(xmm5, xmm0);
+
+	data_len--;
+
+	while(data_len)
+	{
+		xmm0 = _mm_load1_ps(data++);
+
+		xmm2 = _mm_shuffle_ps(xmm2, xmm2, _MM_SHUFFLE(2,1,0,3));
+		xmm3 = _mm_shuffle_ps(xmm3, xmm3, _MM_SHUFFLE(2,1,0,3));
+		xmm4 = _mm_shuffle_ps(xmm4, xmm4, _MM_SHUFFLE(2,1,0,3));
+		xmm4 = _mm_move_ss(xmm4, xmm3);
+		xmm3 = _mm_move_ss(xmm3, xmm2);
+		xmm2 = _mm_move_ss(xmm2, xmm0);
+
+		xmm1 = xmm0;
+		xmm1 = _mm_mul_ps(xmm1, xmm2);
+		xmm5 = _mm_add_ps(xmm5, xmm1);
+		xmm1 = xmm0;
+		xmm1 = _mm_mul_ps(xmm1, xmm3);
+		xmm6 = _mm_add_ps(xmm6, xmm1);
+		xmm0 = _mm_mul_ps(xmm0, xmm4);
+		xmm7 = _mm_add_ps(xmm7, xmm0);
+
+		data_len--;
+	}
+
+	_mm_storeu_ps(autoc,   xmm5);
+	_mm_storeu_ps(autoc+4, xmm6);
+	_mm_storeu_ps(autoc+8, xmm7);
+}
+
+FLAC__SSE_TARGET("sse")
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	__m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9;
+
+	(void) lag;
+	FLAC__ASSERT(lag > 0);
+	FLAC__ASSERT(lag <= 16);
+	FLAC__ASSERT(lag <= data_len);
+	FLAC__ASSERT(data_len > 0);
+
+	xmm6 = _mm_setzero_ps();
+	xmm7 = _mm_setzero_ps();
+	xmm8 = _mm_setzero_ps();
+	xmm9 = _mm_setzero_ps();
+
+	xmm0 = _mm_load_ss(data++);
+	xmm2 = xmm0;
+	xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0);
+	xmm3 = _mm_setzero_ps();
+	xmm4 = _mm_setzero_ps();
+	xmm5 = _mm_setzero_ps();
+
+	xmm0 = _mm_mul_ps(xmm0, xmm2);
+	xmm6 = _mm_add_ps(xmm6, xmm0);
+
+	data_len--;
+
+	while(data_len)
+	{
+		xmm0 = _mm_load1_ps(data++);
+
+		/* shift xmm5:xmm4:xmm3:xmm2 left by one float */
+		xmm5 = _mm_shuffle_ps(xmm5, xmm5, _MM_SHUFFLE(2,1,0,3));
+		xmm4 = _mm_shuffle_ps(xmm4, xmm4, _MM_SHUFFLE(2,1,0,3));
+		xmm3 = _mm_shuffle_ps(xmm3, xmm3, _MM_SHUFFLE(2,1,0,3));
+		xmm2 = _mm_shuffle_ps(xmm2, xmm2, _MM_SHUFFLE(2,1,0,3));
+		xmm5 = _mm_move_ss(xmm5, xmm4);
+		xmm4 = _mm_move_ss(xmm4, xmm3);
+		xmm3 = _mm_move_ss(xmm3, xmm2);
+		xmm2 = _mm_move_ss(xmm2, xmm0);
+
+		/* xmm9|xmm8|xmm7|xmm6 += xmm0|xmm0|xmm0|xmm0 * xmm5|xmm4|xmm3|xmm2 */
+		xmm1 = xmm0;
+		xmm1 = _mm_mul_ps(xmm1, xmm5);
+		xmm9 = _mm_add_ps(xmm9, xmm1);
+		xmm1 = xmm0;
+		xmm1 = _mm_mul_ps(xmm1, xmm4);
+		xmm8 = _mm_add_ps(xmm8, xmm1);
+		xmm1 = xmm0;
+		xmm1 = _mm_mul_ps(xmm1, xmm3);
+		xmm7 = _mm_add_ps(xmm7, xmm1);
+		xmm0 = _mm_mul_ps(xmm0, xmm2);
+		xmm6 = _mm_add_ps(xmm6, xmm0);
+
+		data_len--;
+	}
+
+	_mm_storeu_ps(autoc,   xmm6);
+	_mm_storeu_ps(autoc+4, xmm7);
+	_mm_storeu_ps(autoc+8, xmm8);
+	_mm_storeu_ps(autoc+12,xmm9);
+}
+
+#endif /* FLAC__SSE_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_sse2.c b/src/libFLAC/lpc_intrin_sse2.c
new file mode 100644
index 0000000..b6ea3d8
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_sse2.c
@@ -0,0 +1,937 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/lpc.h"
+#ifdef FLAC__SSE2_SUPPORTED
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+
+#include <emmintrin.h> /* SSE2 */
+
+#define RESIDUAL32_RESULT(xmmN) residual[i] = data[i] - (_mm_cvtsi128_si32(xmmN) >> lp_quantization);
+#define     DATA32_RESULT(xmmN) data[i] = residual[i] + (_mm_cvtsi128_si32(xmmN) >> lp_quantization);
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+	int i;
+	FLAC__int32 sum;
+	const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+					q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+					q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+					q10 = _mm_cvtsi32_si128(0xffff & qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
+					q11 = _mm_cvtsi32_si128(0xffff & qlp_coeff[11]); q11 = _mm_shuffle_epi32(q11, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q11, _mm_loadu_si128((const __m128i*)(data+i-12)));
+						mull = _mm_madd_epi16(q10, _mm_loadu_si128((const __m128i*)(data+i-11))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 11 */
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+					q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+					q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+					q10 = _mm_cvtsi32_si128(0xffff & qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q10, _mm_loadu_si128((const __m128i*)(data+i-11)));
+						mull = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+					q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+					q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(data+i-10)));
+						mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 9 */
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+					q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(data+i-9)));
+						mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(data+i-8)));
+						mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 7 */
+					__m128i q0, q1, q2, q3, q4, q5, q6;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(data+i-7)));
+						mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					__m128i q0, q1, q2, q3, q4, q5;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(data+i-6)));
+						mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 5 */
+					__m128i q0, q1, q2, q3, q4;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(data+i-5)));
+						mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					__m128i q0, q1, q2, q3;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(data+i-4)));
+						mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 3 */
+					__m128i q0, q1, q2;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(data+i-3)));
+						mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					__m128i q0, q1;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(data+i-2)));
+						mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 1 */
+					__m128i q0;
+					q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ;
+						summ = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(data+i-1)));
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		for(; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+				case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+				case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+				case 9:  sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+				case 8:  sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+				case 7:  sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+				case 6:  sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+				case 5:  sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+				case 4:  sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+				case 3:  sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+				case 2:  sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+				case 1:  sum += qlp_coeff[ 0] * data[i- 1];
+			}
+			residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				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);
+		}
+	}
+}
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+	int i;
+
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	if(order <= 12) {
+		if(order > 8) { /* order == 9, 10, 11, 12 */
+			if(order > 10) { /* order == 11, 12 */
+				if(order == 12) {
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));  // 0  0  q[1]  q[0]
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));  // 0  0  q[3]  q[2]
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));  // 0  0  q[5]  q[4]
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));  // 0  0  q[7]  q[6]
+					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));  // 0  0  q[9]  q[8]
+					xmm5 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+10)); // 0  0  q[11] q[10]
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); // 0  q[1]  0  q[0]
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); // 0  q[3]  0  q[2]
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); // 0  q[5]  0  q[4]
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); // 0  q[7]  0  q[6]
+					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); // 0  q[9]  0  q[8]
+					xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(3,1,2,0)); // 0  q[11] 0  q[10]
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum += qlp_coeff[11] * data[i-12];
+						//sum += qlp_coeff[10] * data[i-11];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-12));  // 0   0        d[i-11]  d[i-12]
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); // 0  d[i-12]   0        d[i-11]
+						xmm7 = _mm_mul_epu32(xmm7, xmm5); /* we use _unsigned_ multiplication and discard high dword of the result values */
+
+						//sum += qlp_coeff[9] * data[i-10];
+						//sum += qlp_coeff[8] * data[i-9];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-10));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm4);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[7] * data[i-8];
+						//sum += qlp_coeff[6] * data[i-7];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm3);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[5] * data[i-6];
+						//sum += qlp_coeff[4] * data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm2);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm1);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+				else { /* order == 11 */
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
+					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
+					xmm5 = _mm_cvtsi32_si128(qlp_coeff[10]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[10] * data[i-11];
+						xmm7 = _mm_cvtsi32_si128(data[i-11]);
+						xmm7 = _mm_mul_epu32(xmm7, xmm5);
+
+						//sum += qlp_coeff[9] * data[i-10];
+						//sum += qlp_coeff[8] * data[i-9];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-10));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm4);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[7] * data[i-8];
+						//sum += qlp_coeff[6] * data[i-7];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm3);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[5] * data[i-6];
+						//sum += qlp_coeff[4] * data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm2);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm1);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+			}
+			else { /* order == 9, 10 */
+				if(order == 10) {
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
+					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum += qlp_coeff[9] * data[i-10];
+						//sum += qlp_coeff[8] * data[i-9];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-10));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epu32(xmm7, xmm4);
+
+						//sum += qlp_coeff[7] * data[i-8];
+						//sum += qlp_coeff[6] * data[i-7];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm3);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[5] * data[i-6];
+						//sum += qlp_coeff[4] * data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm2);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm1);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+				else { /* order == 9 */
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
+					xmm4 = _mm_cvtsi32_si128(qlp_coeff[8]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[8] * data[i-9];
+						xmm7 = _mm_cvtsi32_si128(data[i-9]);
+						xmm7 = _mm_mul_epu32(xmm7, xmm4);
+
+						//sum += qlp_coeff[7] * data[i-8];
+						//sum += qlp_coeff[6] * data[i-7];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm3);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[5] * data[i-6];
+						//sum += qlp_coeff[4] * data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm2);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm1);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+			}
+		}
+		else if(order > 4) { /* order == 5, 6, 7, 8 */
+			if(order > 6) { /* order == 7, 8 */
+				if(order == 8) {
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum += qlp_coeff[7] * data[i-8];
+						//sum += qlp_coeff[6] * data[i-7];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epu32(xmm7, xmm3);
+
+						//sum += qlp_coeff[5] * data[i-6];
+						//sum += qlp_coeff[4] * data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm2);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm1);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+				else { /* order == 7 */
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_cvtsi32_si128(qlp_coeff[6]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[6] * data[i-7];
+						xmm7 = _mm_cvtsi32_si128(data[i-7]);
+						xmm7 = _mm_mul_epu32(xmm7, xmm3);
+
+						//sum += qlp_coeff[5] * data[i-6];
+						//sum += qlp_coeff[4] * data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm2);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm1);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+			}
+			else { /* order == 5, 6 */
+				if(order == 6) {
+					__m128i xmm0, xmm1, xmm2, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum += qlp_coeff[5] * data[i-6];
+						//sum += qlp_coeff[4] * data[i-5];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epu32(xmm7, xmm2);
+
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm1);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+				else { /* order == 5 */
+					__m128i xmm0, xmm1, xmm2, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_cvtsi32_si128(qlp_coeff[4]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[4] * data[i-5];
+						xmm7 = _mm_cvtsi32_si128(data[i-5]);
+						xmm7 = _mm_mul_epu32(xmm7, xmm2);
+
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm1);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+			}
+		}
+		else { /* order == 1, 2, 3, 4 */
+			if(order > 2) { /* order == 3, 4 */
+				if(order == 4) {
+					__m128i xmm0, xmm1, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum += qlp_coeff[3] * data[i-4];
+						//sum += qlp_coeff[2] * data[i-3];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epu32(xmm7, xmm1);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+				else { /* order == 3 */
+					__m128i xmm0, xmm1, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_cvtsi32_si128(qlp_coeff[2]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[2] * data[i-3];
+						xmm7 = _mm_cvtsi32_si128(data[i-3]);
+						xmm7 = _mm_mul_epu32(xmm7, xmm1);
+
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epu32(xmm6, xmm0);
+						xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+			}
+			else { /* order == 1, 2 */
+				if(order == 2) {
+					__m128i xmm0, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum += qlp_coeff[1] * data[i-2];
+						//sum += qlp_coeff[0] * data[i-1];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epu32(xmm7, xmm0);
+
+						xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL32_RESULT(xmm7);
+					}
+				}
+				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 */
+		FLAC__int32 sum;
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				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 /* FLAC__SSE2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_sse41.c b/src/libFLAC/lpc_intrin_sse41.c
new file mode 100644
index 0000000..4ef3d3e
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_sse41.c
@@ -0,0 +1,1494 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/lpc.h"
+#ifdef FLAC__SSE4_1_SUPPORTED
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+
+#include <smmintrin.h> /* SSE4.1 */
+
+#if defined FLAC__CPU_IA32 /* unused for x64 */
+
+#define RESIDUAL64_RESULT(xmmN)  residual[i] = data[i] - _mm_cvtsi128_si32(_mm_srl_epi64(xmmN, cnt))
+#define RESIDUAL64_RESULT1(xmmN) residual[i] = data[i] - _mm_cvtsi128_si32(_mm_srli_epi64(xmmN, lp_quantization))
+
+FLAC__SSE_TARGET("sse4.1")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+	int i;
+	const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+	FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm_sra_epi64() so we have to use _mm_srl_epi64() */
+
+	if(order <= 12) {
+		if(order > 8) { /* order == 9, 10, 11, 12 */
+			if(order > 10) { /* order == 11, 12 */
+				if(order == 12) {
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));  // 0  0  q[1]  q[0]
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));  // 0  0  q[3]  q[2]
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));  // 0  0  q[5]  q[4]
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));  // 0  0  q[7]  q[6]
+					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));  // 0  0  q[9]  q[8]
+					xmm5 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+10)); // 0  0  q[11] q[10]
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); // 0  q[1]  0  q[0]
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); // 0  q[3]  0  q[2]
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); // 0  q[5]  0  q[4]
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); // 0  q[7]  0  q[6]
+					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); // 0  q[9]  0  q[8]
+					xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(3,1,2,0)); // 0  q[11] 0  q[10]
+
+					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];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-12));  // 0   0        d[i-11]  d[i-12]
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); // 0  d[i-12]   0        d[i-11]
+						xmm7 = _mm_mul_epi32(xmm7, xmm5);
+
+						//sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						//sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-10));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm4);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						//sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm3);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm2);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm1);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT1(xmm7);
+					}
+				}
+				else { /* order == 11 */
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
+					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
+					xmm5 = _mm_cvtsi32_si128(qlp_coeff[10]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[10] * (FLAC__int64)data[i-11];
+						xmm7 = _mm_cvtsi32_si128(data[i-11]);
+						xmm7 = _mm_mul_epi32(xmm7, xmm5);
+
+						//sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						//sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-10));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm4);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						//sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm3);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm2);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm1);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT1(xmm7);
+					}
+				}
+			}
+			else { /* order == 9, 10 */
+				if(order == 10) {
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
+					xmm4 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+8));
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+					xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
+
+					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];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-10));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epi32(xmm7, xmm4);
+
+						//sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						//sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm3);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm2);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm1);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+				else { /* order == 9 */
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
+					xmm4 = _mm_cvtsi32_si128(qlp_coeff[8]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[8] * (FLAC__int64)data[i-9];
+						xmm7 = _mm_cvtsi32_si128(data[i-9]);
+						xmm7 = _mm_mul_epi32(xmm7, xmm4);
+
+						//sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						//sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm3);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm2);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm1);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+			}
+		}
+		else if(order > 4) { /* order == 5, 6, 7, 8 */
+			if(order > 6) { /* order == 7, 8 */
+				if(order == 8) {
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+6));
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+					xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+
+					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];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-8));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epi32(xmm7, xmm3);
+
+						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm2);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm1);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+				else { /* order == 7 */
+					__m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+					xmm3 = _mm_cvtsi32_si128(qlp_coeff[6]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[6] * (FLAC__int64)data[i-7];
+						xmm7 = _mm_cvtsi32_si128(data[i-7]);
+						xmm7 = _mm_mul_epi32(xmm7, xmm3);
+
+						//sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						//sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm2);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm1);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+			}
+			else { /* order == 5, 6 */
+				if(order == 6) {
+					__m128i xmm0, xmm1, xmm2, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+4));
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+					xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+
+					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];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-6));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epi32(xmm7, xmm2);
+
+						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm1);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+				else { /* order == 5 */
+					__m128i xmm0, xmm1, xmm2, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+					xmm2 = _mm_cvtsi32_si128(qlp_coeff[4]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[4] * (FLAC__int64)data[i-5];
+						xmm7 = _mm_cvtsi32_si128(data[i-5]);
+						xmm7 = _mm_mul_epi32(xmm7, xmm2);
+
+						//sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						//sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm1);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+			}
+		}
+		else { /* order == 1, 2, 3, 4 */
+			if(order > 2) { /* order == 3, 4 */
+				if(order == 4) {
+					__m128i xmm0, xmm1, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+2));
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+					xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+
+					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];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-4));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epi32(xmm7, xmm1);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+				else { /* order == 3 */
+					__m128i xmm0, xmm1, xmm6, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm1 = _mm_cvtsi32_si128(qlp_coeff[2]);
+
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = 0;
+						//sum  = qlp_coeff[2] * (FLAC__int64)data[i-3];
+						xmm7 = _mm_cvtsi32_si128(data[i-3]);
+						xmm7 = _mm_mul_epi32(xmm7, xmm1);
+
+						//sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						//sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm6 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+						xmm6 = _mm_mul_epi32(xmm6, xmm0);
+						xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+			}
+			else { /* order == 1, 2 */
+				if(order == 2) {
+					__m128i xmm0, xmm7;
+					xmm0 = _mm_loadl_epi64((const __m128i*)(qlp_coeff+0));
+					xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+
+					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];
+						xmm7 = _mm_loadl_epi64((const __m128i*)(data+i-2));
+						xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+						xmm7 = _mm_mul_epi32(xmm7, xmm0);
+
+						xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+				else { /* order == 1 */
+					__m128i xmm0, xmm7;
+					xmm0 = _mm_cvtsi32_si128(qlp_coeff[0]);
+
+					for(i = 0; i < (int)data_len; i++) {
+						//sum = qlp_coeff[0] * (FLAC__int64)data[i-1];
+						xmm7 = _mm_cvtsi32_si128(data[i-1]);
+						xmm7 = _mm_mul_epi32(xmm7, xmm0);
+						RESIDUAL64_RESULT(xmm7);
+					}
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		FLAC__int64 sum;
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+				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);
+		}
+	}
+}
+
+FLAC__SSE_TARGET("sse4.1")
+void FLAC__lpc_restore_signal_wide_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[])
+{
+	int i;
+	const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+	if (!data_len)
+		return;
+
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+	FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm_sra_epi64() so we have to use _mm_srl_epi64() */
+
+	if(order <= 12) {
+		if(order > 8) { /* order == 9, 10, 11, 12 */
+			if(order > 10) { /* order == 11, 12 */
+				__m128i qlp[6], dat[6];
+				__m128i summ, temp;
+				qlp[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+0)));		// 0  q[1]  0  q[0]
+				qlp[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+2)));		// 0  q[3]  0  q[2]
+				qlp[2] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+4)));		// 0  q[5]  0  q[4]
+				qlp[3] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+6)));		// 0  q[7]  0  q[6]
+				qlp[4] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+8)));		// 0  q[9]  0  q[8]
+				if (order == 12)
+					qlp[5] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+10)));	// 0  q[11] 0  q[10]
+				else
+					qlp[5] = _mm_cvtepu32_epi64(_mm_cvtsi32_si128(qlp_coeff[10]));					// 0    0   0  q[10]
+
+				dat[5] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-12)), _MM_SHUFFLE(2,0,3,1));	// 0  d[i-12] 0  d[i-11]
+				dat[4] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-10)), _MM_SHUFFLE(2,0,3,1));	// 0  d[i-10] 0  d[i-9]
+				dat[3] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-8 )), _MM_SHUFFLE(2,0,3,1));	// 0  d[i-8]  0  d[i-7]
+				dat[2] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-6 )), _MM_SHUFFLE(2,0,3,1));	// 0  d[i-6]  0  d[i-5]
+				dat[1] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-4 )), _MM_SHUFFLE(2,0,3,1));	// 0  d[i-4]  0  d[i-3]
+				dat[0] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-2 )), _MM_SHUFFLE(2,0,3,1));	// 0  d[i-2]  0  d[i-1]
+
+				summ =                     _mm_mul_epi32(dat[5], qlp[5]) ;
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[4], qlp[4]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[3], qlp[3]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));	// ?_64  sum_64
+				summ = _mm_srl_epi64(summ, cnt);						// ?_64  (sum >> lp_quantization)_64  ==  ?_32  ?_32  ?_32  (sum >> lp_quantization)_32
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[0]), summ);	// ?  ?  ?  d[i]
+				data[0] = _mm_cvtsi128_si32(temp);
+
+				for(i = 1; i < (int)data_len; i++) {
+					temp = _mm_slli_si128(temp, 8);
+					dat[5] = _mm_alignr_epi8(dat[5], dat[4], 8);	//  ?  d[i-11] ?  d[i-10]
+					dat[4] = _mm_alignr_epi8(dat[4], dat[3], 8);	//  ?  d[i-9]  ?  d[i-8]
+					dat[3] = _mm_alignr_epi8(dat[3], dat[2], 8);	//  ?  d[i-7]  ?  d[i-6]
+					dat[2] = _mm_alignr_epi8(dat[2], dat[1], 8);	//  ?  d[i-5]  ?  d[i-4]
+					dat[1] = _mm_alignr_epi8(dat[1], dat[0], 8);	//  ?  d[i-3]  ?  d[i-2]
+					dat[0] = _mm_alignr_epi8(dat[0],   temp, 8);	//  ?  d[i-1]  ?  d[i  ]
+
+					summ =                     _mm_mul_epi32(dat[5], qlp[5]) ;
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[4], qlp[4]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[3], qlp[3]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));	// ?_64  sum_64
+					summ = _mm_srl_epi64(summ, cnt);						// ?_64  (sum >> lp_quantization)_64  ==  ?_32  ?_32  ?_32  (sum >> lp_quantization)_32
+					temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);	// ?  ?  ?  d[i]
+					data[i] = _mm_cvtsi128_si32(temp);
+				}
+			}
+			else { /* order == 9, 10 */
+				__m128i qlp[5], dat[5];
+				__m128i summ, temp;
+				qlp[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+0)));
+				qlp[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+2)));
+				qlp[2] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+4)));
+				qlp[3] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+6)));
+				if (order == 10)
+					qlp[4] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+8)));
+				else
+					qlp[4] = _mm_cvtepu32_epi64(_mm_cvtsi32_si128(qlp_coeff[8]));
+
+				dat[4] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-10)), _MM_SHUFFLE(2,0,3,1));
+				dat[3] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-8 )), _MM_SHUFFLE(2,0,3,1));
+				dat[2] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-6 )), _MM_SHUFFLE(2,0,3,1));
+				dat[1] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-4 )), _MM_SHUFFLE(2,0,3,1));
+				dat[0] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-2 )), _MM_SHUFFLE(2,0,3,1));
+
+				summ =                     _mm_mul_epi32(dat[4], qlp[4]) ;
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[3], qlp[3]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+				summ = _mm_srl_epi64(summ, cnt);
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[0]), summ);
+				data[0] = _mm_cvtsi128_si32(temp);
+
+				for(i = 1; i < (int)data_len; i++) {
+					temp = _mm_slli_si128(temp, 8);
+					dat[4] = _mm_alignr_epi8(dat[4], dat[3], 8);
+					dat[3] = _mm_alignr_epi8(dat[3], dat[2], 8);
+					dat[2] = _mm_alignr_epi8(dat[2], dat[1], 8);
+					dat[1] = _mm_alignr_epi8(dat[1], dat[0], 8);
+					dat[0] = _mm_alignr_epi8(dat[0],   temp, 8);
+
+					summ =                     _mm_mul_epi32(dat[4], qlp[4]) ;
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[3], qlp[3]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+					summ = _mm_srl_epi64(summ, cnt);
+					temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+					data[i] = _mm_cvtsi128_si32(temp);
+				}
+			}
+		}
+		else if(order > 4) { /* order == 5, 6, 7, 8 */
+			if(order > 6) { /* order == 7, 8 */
+				__m128i qlp[4], dat[4];
+				__m128i summ, temp;
+				qlp[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+0)));
+				qlp[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+2)));
+				qlp[2] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+4)));
+				if (order == 8)
+					qlp[3] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+6)));
+				else
+					qlp[3] = _mm_cvtepu32_epi64(_mm_cvtsi32_si128(qlp_coeff[6]));
+
+				dat[3] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-8 )), _MM_SHUFFLE(2,0,3,1));
+				dat[2] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-6 )), _MM_SHUFFLE(2,0,3,1));
+				dat[1] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-4 )), _MM_SHUFFLE(2,0,3,1));
+				dat[0] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-2 )), _MM_SHUFFLE(2,0,3,1));
+
+				summ =                     _mm_mul_epi32(dat[3], qlp[3]) ;
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+				summ = _mm_srl_epi64(summ, cnt);
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[0]), summ);
+				data[0] = _mm_cvtsi128_si32(temp);
+
+				for(i = 1; i < (int)data_len; i++) {
+					temp = _mm_slli_si128(temp, 8);
+					dat[3] = _mm_alignr_epi8(dat[3], dat[2], 8);
+					dat[2] = _mm_alignr_epi8(dat[2], dat[1], 8);
+					dat[1] = _mm_alignr_epi8(dat[1], dat[0], 8);
+					dat[0] = _mm_alignr_epi8(dat[0],   temp, 8);
+
+					summ =                     _mm_mul_epi32(dat[3], qlp[3]) ;
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[2], qlp[2]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+					summ = _mm_srl_epi64(summ, cnt);
+					temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+					data[i] = _mm_cvtsi128_si32(temp);
+				}
+			}
+			else { /* order == 5, 6 */
+				__m128i qlp[3], dat[3];
+				__m128i summ, temp;
+				qlp[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+0)));
+				qlp[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+2)));
+				if (order == 6)
+					qlp[2] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+4)));
+				else
+					qlp[2] = _mm_cvtepu32_epi64(_mm_cvtsi32_si128(qlp_coeff[4]));
+
+				dat[2] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-6 )), _MM_SHUFFLE(2,0,3,1));
+				dat[1] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-4 )), _MM_SHUFFLE(2,0,3,1));
+				dat[0] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-2 )), _MM_SHUFFLE(2,0,3,1));
+
+				summ =                     _mm_mul_epi32(dat[2], qlp[2]) ;
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+				summ = _mm_srl_epi64(summ, cnt);
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[0]), summ);
+				data[0] = _mm_cvtsi128_si32(temp);
+
+				for(i = 1; i < (int)data_len; i++) {
+					temp = _mm_slli_si128(temp, 8);
+					dat[2] = _mm_alignr_epi8(dat[2], dat[1], 8);
+					dat[1] = _mm_alignr_epi8(dat[1], dat[0], 8);
+					dat[0] = _mm_alignr_epi8(dat[0],   temp, 8);
+
+					summ =                     _mm_mul_epi32(dat[2], qlp[2]) ;
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[1], qlp[1]));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+					summ = _mm_srl_epi64(summ, cnt);
+					temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+					data[i] = _mm_cvtsi128_si32(temp);
+				}
+			}
+		}
+		else { /* order == 1, 2, 3, 4 */
+			if(order > 2) { /* order == 3, 4 */
+				__m128i qlp[2], dat[2];
+				__m128i summ, temp;
+				qlp[0] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+0)));
+				if (order == 4)
+					qlp[1] = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff+2)));
+				else
+					qlp[1] = _mm_cvtepu32_epi64(_mm_cvtsi32_si128(qlp_coeff[2]));
+
+				dat[1] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-4 )), _MM_SHUFFLE(2,0,3,1));
+				dat[0] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-2 )), _MM_SHUFFLE(2,0,3,1));
+
+				summ =                     _mm_mul_epi32(dat[1], qlp[1]) ;
+				summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+				summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+				summ = _mm_srl_epi64(summ, cnt);
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[0]), summ);
+				data[0] = _mm_cvtsi128_si32(temp);
+
+				for(i = 1; i < (int)data_len; i++) {
+					temp = _mm_slli_si128(temp, 8);
+					dat[1] = _mm_alignr_epi8(dat[1], dat[0], 8);
+					dat[0] = _mm_alignr_epi8(dat[0],   temp, 8);
+
+					summ =                     _mm_mul_epi32(dat[1], qlp[1]) ;
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat[0], qlp[0]));
+
+					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+					summ = _mm_srl_epi64(summ, cnt);
+					temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+					data[i] = _mm_cvtsi128_si32(temp);
+				}
+			}
+			else { /* order == 1, 2 */
+				if(order == 2) {
+					__m128i qlp0, dat0;
+					__m128i summ, temp;
+					qlp0 = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(qlp_coeff)));
+
+					dat0 = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(data-2 )), _MM_SHUFFLE(2,0,3,1));
+
+					summ = _mm_mul_epi32(dat0, qlp0);
+
+					summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+					summ = _mm_srl_epi64(summ, cnt);
+					temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[0]), summ);
+					data[0] = _mm_cvtsi128_si32(temp);
+
+					for(i = 1; i < (int)data_len; i++) {
+						dat0 = _mm_alignr_epi8(dat0, _mm_slli_si128(temp, 8), 8);
+
+						summ = _mm_mul_epi32(dat0, qlp0);
+
+						summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+						summ = _mm_srl_epi64(summ, cnt);
+						temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+						data[i] = _mm_cvtsi128_si32(temp);
+					}
+				}
+				else { /* order == 1 */
+					__m128i qlp0;
+					__m128i summ, temp;
+					qlp0 = _mm_cvtsi32_si128(qlp_coeff[0]);
+					temp = _mm_cvtsi32_si128(data[-1]);
+
+					summ = _mm_mul_epi32(temp, qlp0);
+					summ = _mm_srl_epi64(summ, cnt);
+					temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[0]), summ);
+					data[0] = _mm_cvtsi128_si32(temp);
+
+					for(i = 1; i < (int)data_len; i++) {
+						summ = _mm_mul_epi32(temp, qlp0);
+						summ = _mm_srl_epi64(summ, cnt);
+						temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+						data[i] = _mm_cvtsi128_si32(temp);
+					}
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		__m128i qlp[16];
+
+		for(i = 0; i < (int)order/2; i++)
+			qlp[i] = _mm_shuffle_epi32(_mm_loadl_epi64((const __m128i*)(qlp_coeff+i*2)), _MM_SHUFFLE(2,0,3,1));	// 0  q[2*i]  0  q[2*i+1]
+		if(order & 1)
+			qlp[i] = _mm_shuffle_epi32(_mm_cvtsi32_si128(qlp_coeff[i*2]), _MM_SHUFFLE(2,0,3,1));
+
+		for(i = 0; i < (int)data_len; i++) {
+			__m128i summ = _mm_setzero_si128(), dat;
+			FLAC__int32 * const datai = &data[i];
+
+			switch((order+1) / 2) {
+				case 16: /* order == 31, 32 */
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-32)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[15]));                /* Falls through. */
+				case 15:
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-30)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[14]));                /* Falls through. */
+				case 14:
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-28)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[13]));                /* Falls through. */
+				case 13:
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-26)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[12]));                /* Falls through. */
+				case 12:
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-24)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[11]));                /* Falls through. */
+				case 11:
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-22)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[10]));                /* Falls through. */
+				case 10:
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-20)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[9]));                 /* Falls through. */
+				case  9:
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-18)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[8]));                 /* Falls through. */
+				case  8:
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-16)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[7]));                 /* Falls through. */
+				case  7: /* order == 13, 14 */
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-14)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[6]));
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-12)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[5]));
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-10)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[4]));
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-8)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[3]));
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-6)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[2]));
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-4)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[1]));
+					dat = _mm_cvtepu32_epi64(_mm_loadl_epi64((const __m128i*)(datai-2)));
+					summ = _mm_add_epi64(summ, _mm_mul_epi32(dat, qlp[0]));
+			}
+			summ = _mm_add_epi64(summ, _mm_srli_si128(summ, 8));
+			summ = _mm_srl_epi64(summ, cnt);
+			summ = _mm_add_epi32(summ, _mm_cvtsi32_si128(residual[i]));
+			data[i] = _mm_cvtsi128_si32(summ);
+		}
+	}
+}
+
+FLAC__SSE_TARGET("sse4.1")
+void FLAC__lpc_restore_signal_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[])
+{
+	if(order < 8) {
+		FLAC__lpc_restore_signal(residual, data_len, qlp_coeff, order, lp_quantization, data);
+		return;
+	}
+
+	FLAC__ASSERT(order >= 8);
+	FLAC__ASSERT(order <= 32);
+
+	if(order <= 12) {
+		int i;
+		const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+		if(order > 8) /* order == 9, 10, 11, 12 */
+		{
+			__m128i qlp[3], dat[3];
+			__m128i summ, temp;
+
+			qlp[0] = _mm_loadu_si128((const __m128i*)(qlp_coeff + 0));	// q[3]  q[2]  q[1]  q[0]
+			qlp[1] = _mm_loadu_si128((const __m128i*)(qlp_coeff + 4));	// q[7]  q[6]  q[5]  q[4]
+			qlp[2] = _mm_loadu_si128((const __m128i*)(qlp_coeff + 8));	// q[11] q[10] q[9]  q[8]
+			switch (order)
+			{
+			case 9:
+				qlp[2] = _mm_slli_si128(qlp[2], 12); qlp[2] = _mm_srli_si128(qlp[2], 12); break;	//   0     0     0   q[8]
+			case 10:
+				qlp[2] = _mm_slli_si128(qlp[2], 8); qlp[2] = _mm_srli_si128(qlp[2], 8); break;	//   0     0   q[9]  q[8]
+			case 11:
+				qlp[2] = _mm_slli_si128(qlp[2], 4); qlp[2] = _mm_srli_si128(qlp[2], 4); break;	//   0   q[10] q[9]  q[8]
+			}
+
+			dat[2] = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data - 12)), _MM_SHUFFLE(0, 1, 2, 3));	// d[i-12] d[i-11] d[i-10] d[i-9]
+			dat[1] = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data - 8)), _MM_SHUFFLE(0, 1, 2, 3));	// d[i-8]  d[i-7]  d[i-6]  d[i-5]
+			dat[0] = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data - 4)), _MM_SHUFFLE(0, 1, 2, 3));	// d[i-4]  d[i-3]  d[i-2]  d[i-1]
+
+			for (i = 0;;) {
+				summ = _mm_mullo_epi32(dat[2], qlp[2]);
+				summ = _mm_add_epi32(summ, _mm_mullo_epi32(dat[1], qlp[1]));
+				summ = _mm_add_epi32(summ, _mm_mullo_epi32(dat[0], qlp[0]));
+
+				summ = _mm_add_epi32(summ, _mm_shuffle_epi32(summ, _MM_SHUFFLE(1,0,3,2)));
+				summ = _mm_add_epi32(summ, _mm_shufflelo_epi16(summ, _MM_SHUFFLE(1,0,3,2)));
+
+				summ = _mm_sra_epi32(summ, cnt);
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+				data[i] = _mm_cvtsi128_si32(temp);
+
+				if(++i >= (int)data_len) break;
+
+				temp = _mm_slli_si128(temp, 12);
+				dat[2] = _mm_alignr_epi8(dat[2], dat[1], 12);
+				dat[1] = _mm_alignr_epi8(dat[1], dat[0], 12);
+				dat[0] = _mm_alignr_epi8(dat[0], temp, 12);
+			}
+		}
+		else /* order == 8 */
+		{
+			__m128i qlp[2], dat[2];
+			__m128i summ, temp;
+
+			qlp[0] = _mm_loadu_si128((const __m128i*)(qlp_coeff + 0));
+			qlp[1] = _mm_loadu_si128((const __m128i*)(qlp_coeff + 4));
+
+			dat[1] = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data - 8)), _MM_SHUFFLE(0, 1, 2, 3));
+			dat[0] = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data - 4)), _MM_SHUFFLE(0, 1, 2, 3));
+
+			for (i = 0;;) {
+				summ = _mm_add_epi32(_mm_mullo_epi32(dat[1], qlp[1]), _mm_mullo_epi32(dat[0], qlp[0]));
+
+				summ = _mm_add_epi32(summ, _mm_shuffle_epi32(summ, _MM_SHUFFLE(1,0,3,2)));
+				summ = _mm_add_epi32(summ, _mm_shufflelo_epi16(summ, _MM_SHUFFLE(1,0,3,2)));
+
+				summ = _mm_sra_epi32(summ, cnt);
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+				data[i] = _mm_cvtsi128_si32(temp);
+
+				if(++i >= (int)data_len) break;
+
+				temp = _mm_slli_si128(temp, 12);
+				dat[1] = _mm_alignr_epi8(dat[1], dat[0], 12);
+				dat[0] = _mm_alignr_epi8(dat[0], temp, 12);
+			}
+		}
+	}
+	else { /* order > 12 */
+#ifdef FLAC__HAS_NASM
+		FLAC__lpc_restore_signal_asm_ia32(residual, data_len, qlp_coeff, order, lp_quantization, data);
+#else
+		FLAC__lpc_restore_signal(residual, data_len, qlp_coeff, order, lp_quantization, data);
+#endif
+	}
+}
+
+FLAC__SSE_TARGET("ssse3")
+void FLAC__lpc_restore_signal_16_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[])
+{
+	if(order < 8) {
+		FLAC__lpc_restore_signal(residual, data_len, qlp_coeff, order, lp_quantization, data);
+		return;
+	}
+
+	FLAC__ASSERT(order >= 8);
+	FLAC__ASSERT(order <= 32);
+
+	if(order <= 12) {
+		int i;
+		const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+		if(order > 8) /* order == 9, 10, 11, 12 */
+		{
+			__m128i qlp[2], dat[2];
+			__m128i summ, temp;
+
+			qlp[0] = _mm_loadu_si128((const __m128i*)(qlp_coeff+0));	// q[3]  q[2]  q[1]  q[0]
+			temp   = _mm_loadu_si128((const __m128i*)(qlp_coeff+4));	// q[7]  q[6]  q[5]  q[4]
+			qlp[1] = _mm_loadu_si128((const __m128i*)(qlp_coeff+8));	// q[11] q[10] q[9]  q[8]
+			switch(order)
+			{
+			case 9:
+				qlp[1] = _mm_slli_si128(qlp[1], 12); qlp[1] = _mm_srli_si128(qlp[1], 12); break;	//   0     0     0   q[8]
+			case 10:
+				qlp[1] = _mm_slli_si128(qlp[1],  8); qlp[1] = _mm_srli_si128(qlp[1],  8); break;	//   0     0   q[9]  q[8]
+			case 11:
+				qlp[1] = _mm_slli_si128(qlp[1],  4); qlp[1] = _mm_srli_si128(qlp[1],  4); break;	//   0   q[10] q[9]  q[8]
+			}
+			qlp[0] = _mm_packs_epi32(qlp[0], temp);					// q[7]  q[6]  q[5]  q[4]  q[3]  q[2]  q[1]  q[0]
+			qlp[1] = _mm_packs_epi32(qlp[1], _mm_setzero_si128());	//   0     0     0     0   q[11] q[10] q[9]  q[8]
+
+			dat[1] = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data-12)), _MM_SHUFFLE(0,1,2,3));	// d[i-12] d[i-11] d[i-10] d[i-9]
+			temp   = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data-8)),  _MM_SHUFFLE(0,1,2,3));	// d[i-8]  d[i-7]  d[i-6]  d[i-5]
+			dat[0] = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data-4)),  _MM_SHUFFLE(0,1,2,3));	// d[i-4]  d[i-3]  d[i-2]  d[i-1]
+
+			dat[1] = _mm_packs_epi32(dat[1], _mm_setzero_si128());		//   0       0       0       0     d[i-12] d[i-11] d[i-10] d[i-9]
+			dat[0] = _mm_packs_epi32(dat[0], temp);						// d[i-8]  d[i-7]  d[i-6]  d[i-5]  d[i-4]  d[i-3]  d[i-2]  d[i-1]
+
+			for(i = 0;;) {
+				summ = _mm_madd_epi16(dat[1], qlp[1]);
+				summ = _mm_add_epi32(summ, _mm_madd_epi16(dat[0], qlp[0]));
+
+				summ = _mm_add_epi32(summ, _mm_shuffle_epi32(summ, _MM_SHUFFLE(1,0,3,2)));
+				summ = _mm_add_epi32(summ, _mm_shufflelo_epi16(summ, _MM_SHUFFLE(1,0,3,2)));
+
+				summ = _mm_sra_epi32(summ, cnt);
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+				data[i] = _mm_cvtsi128_si32(temp);
+
+				if(++i >= (int)data_len) break;
+
+				temp = _mm_slli_si128(temp, 14);
+				dat[1] = _mm_alignr_epi8(dat[1], dat[0], 14);	//   0       0       0     d[i-12] d[i-11] d[i-10] d[i-9]  d[i-8]
+				dat[0] = _mm_alignr_epi8(dat[0],   temp, 14);	// d[i-7]  d[i-6]  d[i-5]  d[i-4]  d[i-3]  d[i-2]  d[i-1]  d[i]
+			}
+		}
+		else /* order == 8 */
+		{
+			__m128i qlp0, dat0;
+			__m128i summ, temp;
+
+			qlp0 = _mm_loadu_si128((const __m128i*)(qlp_coeff+0));	// q[3]  q[2]  q[1]  q[0]
+			temp = _mm_loadu_si128((const __m128i*)(qlp_coeff+4));	// q[7]  q[6]  q[5]  q[4]
+			qlp0 = _mm_packs_epi32(qlp0, temp);						// q[7]  q[6]  q[5]  q[4]  q[3]  q[2]  q[1]  q[0]
+
+			temp = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data-8)), _MM_SHUFFLE(0,1,2,3));
+			dat0 = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data-4)), _MM_SHUFFLE(0,1,2,3));
+			dat0 = _mm_packs_epi32(dat0, temp);						// d[i-8]  d[i-7]  d[i-6]  d[i-5]  d[i-4]  d[i-3]  d[i-2]  d[i-1]
+
+			for(i = 0;;) {
+				summ = _mm_madd_epi16(dat0, qlp0);
+
+				summ = _mm_add_epi32(summ, _mm_shuffle_epi32(summ, _MM_SHUFFLE(1,0,3,2)));
+				summ = _mm_add_epi32(summ, _mm_shufflelo_epi16(summ, _MM_SHUFFLE(1,0,3,2)));
+
+				summ = _mm_sra_epi32(summ, cnt);
+				temp = _mm_add_epi32(_mm_cvtsi32_si128(residual[i]), summ);
+				data[i] = _mm_cvtsi128_si32(temp);
+
+				if(++i >= (int)data_len) break;
+
+				temp = _mm_slli_si128(temp, 14);
+				dat0 = _mm_alignr_epi8(dat0, temp, 14);	// d[i-7]  d[i-6]  d[i-5]  d[i-4]  d[i-3]  d[i-2]  d[i-1]  d[i]
+			}
+		}
+	}
+	else { /* order > 12 */
+#ifdef FLAC__HAS_NASM
+		FLAC__lpc_restore_signal_asm_ia32_mmx(residual, data_len, qlp_coeff, order, lp_quantization, data);
+#else
+		FLAC__lpc_restore_signal(residual, data_len, qlp_coeff, order, lp_quantization, data);
+#endif
+	}
+}
+
+#endif /* defined FLAC__CPU_IA32 */
+
+FLAC__SSE_TARGET("sse4.1")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+	int i;
+	FLAC__int32 sum;
+	const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+					q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+					q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+					q10 = _mm_cvtsi32_si128(qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
+					q11 = _mm_cvtsi32_si128(qlp_coeff[11]); q11 = _mm_shuffle_epi32(q11, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q11, _mm_loadu_si128((const __m128i*)(data+i-12)));
+						mull = _mm_mullo_epi32(q10, _mm_loadu_si128((const __m128i*)(data+i-11))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 11 */
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+					q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+					q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+					q10 = _mm_cvtsi32_si128(qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q10, _mm_loadu_si128((const __m128i*)(data+i-11)));
+						mull = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+					q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+					q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(data+i-10)));
+						mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 9 */
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+					q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(data+i-9)));
+						mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					__m128i q0, q1, q2, q3, q4, q5, q6, q7;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+					q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(data+i-8)));
+						mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 7 */
+					__m128i q0, q1, q2, q3, q4, q5, q6;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+					q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(data+i-7)));
+						mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					__m128i q0, q1, q2, q3, q4, q5;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+					q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(data+i-6)));
+						mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 5 */
+					__m128i q0, q1, q2, q3, q4;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+					q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(data+i-5)));
+						mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					__m128i q0, q1, q2, q3;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+					q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(data+i-4)));
+						mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 3 */
+					__m128i q0, q1, q2;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+					q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(data+i-3)));
+						mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					__m128i q0, q1;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+					q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ, mull;
+						summ = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(data+i-2)));
+						mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+				else { /* order == 1 */
+					__m128i q0;
+					q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+
+					for(i = 0; i < (int)data_len-3; i+=4) {
+						__m128i summ;
+						summ = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(data+i-1)));
+						summ = _mm_sra_epi32(summ, cnt);
+						_mm_storeu_si128((__m128i*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(data+i)), summ));
+					}
+				}
+			}
+		}
+		for(; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+				case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+				case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+				case 9:  sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+				case 8:  sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+				case 7:  sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+				case 6:  sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+				case 5:  sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+				case 4:  sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+				case 3:  sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+				case 2:  sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+				case 1:  sum += qlp_coeff[ 0] * data[i- 1];
+			}
+			residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				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 /* FLAC__SSE4_1_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_vsx.c b/src/libFLAC/lpc_intrin_vsx.c
new file mode 100644
index 0000000..48c8218
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_vsx.c
@@ -0,0 +1,942 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if defined(FLAC__CPU_PPC64) && defined(FLAC__USE_VSX)
+
+#include "private/cpu.h"
+#include "private/lpc.h"
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+
+#include <altivec.h>
+
+#ifdef FLAC__HAS_TARGET_POWER8
+__attribute__((target("cpu=power8")))
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	long i;
+	long limit = (long)data_len - 16;
+	const FLAC__real *base;
+	vector float sum0 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum1 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum2 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum3 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum10 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum11 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum12 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum13 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum20 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum21 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum22 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum23 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum30 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum31 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum32 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum33 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float d0, d1, d2, d3, d4;
+#if WORDS_BIGENDIAN
+	vector unsigned int vsel1 = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+	vector unsigned int vsel2 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vsel3 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vperm1 = { 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213 };
+	vector unsigned int vperm2 = { 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617 };
+	vector unsigned int vperm3 = { 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B };
+#else
+	vector unsigned int vsel1 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+	vector unsigned int vsel2 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+	vector unsigned int vsel3 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+	vector unsigned int vperm1 = { 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110 };
+	vector unsigned int vperm2 = { 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514 };
+	vector unsigned int vperm3 = { 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918 };
+#endif
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 16);
+	FLAC__ASSERT(lag <= data_len);
+
+	base = data;
+
+	d0 = vec_vsx_ld(0, base);
+	d1 = vec_vsx_ld(16, base);
+	d2 = vec_vsx_ld(32, base);
+	d3 = vec_vsx_ld(48, base);
+
+	base += 16;
+
+	for (i = 0; i <= (limit-4); i += 4) {
+		vector float d, d0_orig = d0;
+
+		d4 = vec_vsx_ld(0, base);
+		base += 4;
+
+		d = vec_splat(d0_orig, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+		sum2 += d2 * d;
+		sum3 += d3 * d;
+
+		d = vec_splat(d0_orig, 1);
+		d0 = vec_sel(d0_orig, d4, vsel1);
+		sum10 += d0 * d;
+		sum11 += d1 * d;
+		sum12 += d2 * d;
+		sum13 += d3 * d;
+
+		d = vec_splat(d0_orig, 2);
+		d0 = vec_sel(d0_orig, d4, vsel2);
+		sum20 += d0 * d;
+		sum21 += d1 * d;
+		sum22 += d2 * d;
+		sum23 += d3 * d;
+
+		d = vec_splat(d0_orig, 3);
+		d0 = vec_sel(d0_orig, d4, vsel3);
+		sum30 += d0 * d;
+		sum31 += d1 * d;
+		sum32 += d2 * d;
+		sum33 += d3 * d;
+
+		d0 = d1;
+		d1 = d2;
+		d2 = d3;
+		d3 = d4;
+	}
+
+	sum0 += vec_perm(sum10, sum11, (vector unsigned char)vperm1);
+	sum1 += vec_perm(sum11, sum12, (vector unsigned char)vperm1);
+	sum2 += vec_perm(sum12, sum13, (vector unsigned char)vperm1);
+	sum3 += vec_perm(sum13, sum10, (vector unsigned char)vperm1);
+
+	sum0 += vec_perm(sum20, sum21, (vector unsigned char)vperm2);
+	sum1 += vec_perm(sum21, sum22, (vector unsigned char)vperm2);
+	sum2 += vec_perm(sum22, sum23, (vector unsigned char)vperm2);
+	sum3 += vec_perm(sum23, sum20, (vector unsigned char)vperm2);
+
+	sum0 += vec_perm(sum30, sum31, (vector unsigned char)vperm3);
+	sum1 += vec_perm(sum31, sum32, (vector unsigned char)vperm3);
+	sum2 += vec_perm(sum32, sum33, (vector unsigned char)vperm3);
+	sum3 += vec_perm(sum33, sum30, (vector unsigned char)vperm3);
+
+	for (; i <= limit; i++) {
+		vector float d;
+
+		d0 = vec_vsx_ld(0, data+i);
+		d1 = vec_vsx_ld(16, data+i);
+		d2 = vec_vsx_ld(32, data+i);
+		d3 = vec_vsx_ld(48, data+i);
+
+		d = vec_splat(d0, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+		sum2 += d2 * d;
+		sum3 += d3 * d;
+	}
+
+	vec_vsx_st(sum0, 0, autoc);
+	vec_vsx_st(sum1, 16, autoc);
+	vec_vsx_st(sum2, 32, autoc);
+	vec_vsx_st(sum3, 48, autoc);
+
+	for (; i < (long)data_len; i++) {
+		uint32_t coeff;
+
+		FLAC__real d = data[i];
+		for (coeff = 0; coeff < data_len - i; coeff++)
+			autoc[coeff] += d * data[i+coeff];
+	}
+}
+
+__attribute__((target("cpu=power8")))
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	long i;
+	long limit = (long)data_len - 12;
+	const FLAC__real *base;
+	vector float sum0 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum1 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum2 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum10 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum11 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum12 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum20 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum21 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum22 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum30 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum31 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum32 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float d0, d1, d2, d3;
+#if WORDS_BIGENDIAN
+	vector unsigned int vsel1 = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+	vector unsigned int vsel2 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vsel3 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vperm1 = { 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213 };
+	vector unsigned int vperm2 = { 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617 };
+	vector unsigned int vperm3 = { 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B };
+#else
+	vector unsigned int vsel1 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+	vector unsigned int vsel2 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+	vector unsigned int vsel3 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+	vector unsigned int vperm1 = { 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110 };
+	vector unsigned int vperm2 = { 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514 };
+	vector unsigned int vperm3 = { 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918 };
+#endif
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 12);
+	FLAC__ASSERT(lag <= data_len);
+
+	base = data;
+
+	d0 = vec_vsx_ld(0, base);
+	d1 = vec_vsx_ld(16, base);
+	d2 = vec_vsx_ld(32, base);
+
+	base += 12;
+
+	for (i = 0; i <= (limit-3); i += 4) {
+		vector float d, d0_orig = d0;
+
+		d3 = vec_vsx_ld(0, base);
+		base += 4;
+
+		d = vec_splat(d0_orig, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+		sum2 += d2 * d;
+
+		d = vec_splat(d0_orig, 1);
+		d0 = vec_sel(d0_orig, d3, vsel1);
+		sum10 += d0 * d;
+		sum11 += d1 * d;
+		sum12 += d2 * d;
+
+		d = vec_splat(d0_orig, 2);
+		d0 = vec_sel(d0_orig, d3, vsel2);
+		sum20 += d0 * d;
+		sum21 += d1 * d;
+		sum22 += d2 * d;
+
+		d = vec_splat(d0_orig, 3);
+		d0 = vec_sel(d0_orig, d3, vsel3);
+		sum30 += d0 * d;
+		sum31 += d1 * d;
+		sum32 += d2 * d;
+
+		d0 = d1;
+		d1 = d2;
+		d2 = d3;
+	}
+
+	sum0 += vec_perm(sum10, sum11, (vector unsigned char)vperm1);
+	sum1 += vec_perm(sum11, sum12, (vector unsigned char)vperm1);
+	sum2 += vec_perm(sum12, sum10, (vector unsigned char)vperm1);
+
+	sum0 += vec_perm(sum20, sum21, (vector unsigned char)vperm2);
+	sum1 += vec_perm(sum21, sum22, (vector unsigned char)vperm2);
+	sum2 += vec_perm(sum22, sum20, (vector unsigned char)vperm2);
+
+	sum0 += vec_perm(sum30, sum31, (vector unsigned char)vperm3);
+	sum1 += vec_perm(sum31, sum32, (vector unsigned char)vperm3);
+	sum2 += vec_perm(sum32, sum30, (vector unsigned char)vperm3);
+
+	for (; i <= limit; i++) {
+		vector float d;
+
+		d0 = vec_vsx_ld(0, data+i);
+		d1 = vec_vsx_ld(16, data+i);
+		d2 = vec_vsx_ld(32, data+i);
+
+		d = vec_splat(d0, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+		sum2 += d2 * d;
+	}
+
+	vec_vsx_st(sum0, 0, autoc);
+	vec_vsx_st(sum1, 16, autoc);
+	vec_vsx_st(sum2, 32, autoc);
+
+	for (; i < (long)data_len; i++) {
+		uint32_t coeff;
+
+		FLAC__real d = data[i];
+		for (coeff = 0; coeff < data_len - i; coeff++)
+			autoc[coeff] += d * data[i+coeff];
+	}
+}
+
+__attribute__((target("cpu=power8")))
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	long i;
+	long limit = (long)data_len - 8;
+	const FLAC__real *base;
+	vector float sum0 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum1 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum10 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum11 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum20 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum21 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum30 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum31 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float d0, d1, d2;
+#if WORDS_BIGENDIAN
+	vector unsigned int vsel1 = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+	vector unsigned int vsel2 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vsel3 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vperm1 = { 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213 };
+	vector unsigned int vperm2 = { 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617 };
+	vector unsigned int vperm3 = { 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B };
+#else
+	vector unsigned int vsel1 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+	vector unsigned int vsel2 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+	vector unsigned int vsel3 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+	vector unsigned int vperm1 = { 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110 };
+	vector unsigned int vperm2 = { 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514 };
+	vector unsigned int vperm3 = { 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918 };
+#endif
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 8);
+	FLAC__ASSERT(lag <= data_len);
+
+	base = data;
+
+	d0 = vec_vsx_ld(0, base);
+	d1 = vec_vsx_ld(16, base);
+
+	base += 8;
+
+	for (i = 0; i <= (limit-2); i += 4) {
+		vector float d, d0_orig = d0;
+
+		d2 = vec_vsx_ld(0, base);
+		base += 4;
+
+		d = vec_splat(d0_orig, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+
+		d = vec_splat(d0_orig, 1);
+		d0 = vec_sel(d0_orig, d2, vsel1);
+		sum10 += d0 * d;
+		sum11 += d1 * d;
+
+		d = vec_splat(d0_orig, 2);
+		d0 = vec_sel(d0_orig, d2, vsel2);
+		sum20 += d0 * d;
+		sum21 += d1 * d;
+
+		d = vec_splat(d0_orig, 3);
+		d0 = vec_sel(d0_orig, d2, vsel3);
+		sum30 += d0 * d;
+		sum31 += d1 * d;
+
+		d0 = d1;
+		d1 = d2;
+	}
+
+	sum0 += vec_perm(sum10, sum11, (vector unsigned char)vperm1);
+	sum1 += vec_perm(sum11, sum10, (vector unsigned char)vperm1);
+
+	sum0 += vec_perm(sum20, sum21, (vector unsigned char)vperm2);
+	sum1 += vec_perm(sum21, sum20, (vector unsigned char)vperm2);
+
+	sum0 += vec_perm(sum30, sum31, (vector unsigned char)vperm3);
+	sum1 += vec_perm(sum31, sum30, (vector unsigned char)vperm3);
+
+	for (; i <= limit; i++) {
+		vector float d;
+
+		d0 = vec_vsx_ld(0, data+i);
+		d1 = vec_vsx_ld(16, data+i);
+
+		d = vec_splat(d0, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+	}
+
+	vec_vsx_st(sum0, 0, autoc);
+	vec_vsx_st(sum1, 16, autoc);
+
+	for (; i < (long)data_len; i++) {
+		uint32_t coeff;
+
+		FLAC__real d = data[i];
+		for (coeff = 0; coeff < data_len - i; coeff++)
+			autoc[coeff] += d * data[i+coeff];
+	}
+}
+
+__attribute__((target("cpu=power8")))
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	long i;
+	long limit = (long)data_len - 4;
+	const FLAC__real *base;
+	vector float sum0 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum10 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum20 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum30 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float d0, d1;
+#if WORDS_BIGENDIAN
+	vector unsigned int vsel1 = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+	vector unsigned int vsel2 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vsel3 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vperm1 = { 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213 };
+	vector unsigned int vperm2 = { 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617 };
+	vector unsigned int vperm3 = { 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B };
+#else
+	vector unsigned int vsel1 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+	vector unsigned int vsel2 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+	vector unsigned int vsel3 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+	vector unsigned int vperm1 = { 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110 };
+	vector unsigned int vperm2 = { 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514 };
+	vector unsigned int vperm3 = { 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918 };
+#endif
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 4);
+	FLAC__ASSERT(lag <= data_len);
+
+	base = data;
+
+	d0 = vec_vsx_ld(0, base);
+
+	base += 4;
+
+	for (i = 0; i <= (limit-1); i += 4) {
+		vector float d, d0_orig = d0;
+
+		d1 = vec_vsx_ld(0, base);
+		base += 4;
+
+		d = vec_splat(d0_orig, 0);
+		sum0 += d0 * d;
+
+		d = vec_splat(d0_orig, 1);
+		d0 = vec_sel(d0_orig, d1, vsel1);
+		sum10 += d0 * d;
+
+		d = vec_splat(d0_orig, 2);
+		d0 = vec_sel(d0_orig, d1, vsel2);
+		sum20 += d0 * d;
+
+		d = vec_splat(d0_orig, 3);
+		d0 = vec_sel(d0_orig, d1, vsel3);
+		sum30 += d0 * d;
+
+		d0 = d1;
+	}
+
+	sum0 += vec_perm(sum10, sum10, (vector unsigned char)vperm1);
+
+	sum0 += vec_perm(sum20, sum20, (vector unsigned char)vperm2);
+
+	sum0 += vec_perm(sum30, sum30, (vector unsigned char)vperm3);
+
+	for (; i <= limit; i++) {
+		vector float d;
+
+		d0 = vec_vsx_ld(0, data+i);
+
+		d = vec_splat(d0, 0);
+		sum0 += d0 * d;
+	}
+
+	vec_vsx_st(sum0, 0, autoc);
+
+	for (; i < (long)data_len; i++) {
+		uint32_t coeff;
+
+		FLAC__real d = data[i];
+		for (coeff = 0; coeff < data_len - i; coeff++)
+			autoc[coeff] += d * data[i+coeff];
+	}
+}
+#endif /* FLAC__HAS_TARGET_POWER8 */
+
+#ifdef FLAC__HAS_TARGET_POWER9
+__attribute__((target("cpu=power9")))
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	long i;
+	long limit = (long)data_len - 16;
+	const FLAC__real *base;
+	vector float sum0 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum1 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum2 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum3 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum10 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum11 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum12 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum13 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum20 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum21 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum22 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum23 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum30 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum31 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum32 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum33 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float d0, d1, d2, d3, d4;
+#if WORDS_BIGENDIAN
+	vector unsigned int vsel1 = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+	vector unsigned int vsel2 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vsel3 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vperm1 = { 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213 };
+	vector unsigned int vperm2 = { 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617 };
+	vector unsigned int vperm3 = { 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B };
+#else
+	vector unsigned int vsel1 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+	vector unsigned int vsel2 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+	vector unsigned int vsel3 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+	vector unsigned int vperm1 = { 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110 };
+	vector unsigned int vperm2 = { 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514 };
+	vector unsigned int vperm3 = { 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918 };
+#endif
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 16);
+	FLAC__ASSERT(lag <= data_len);
+
+	base = data;
+
+	d0 = vec_vsx_ld(0, base);
+	d1 = vec_vsx_ld(16, base);
+	d2 = vec_vsx_ld(32, base);
+	d3 = vec_vsx_ld(48, base);
+
+	base += 16;
+
+	for (i = 0; i <= (limit-4); i += 4) {
+		vector float d, d0_orig = d0;
+
+		d4 = vec_vsx_ld(0, base);
+		base += 4;
+
+		d = vec_splat(d0_orig, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+		sum2 += d2 * d;
+		sum3 += d3 * d;
+
+		d = vec_splat(d0_orig, 1);
+		d0 = vec_sel(d0_orig, d4, vsel1);
+		sum10 += d0 * d;
+		sum11 += d1 * d;
+		sum12 += d2 * d;
+		sum13 += d3 * d;
+
+		d = vec_splat(d0_orig, 2);
+		d0 = vec_sel(d0_orig, d4, vsel2);
+		sum20 += d0 * d;
+		sum21 += d1 * d;
+		sum22 += d2 * d;
+		sum23 += d3 * d;
+
+		d = vec_splat(d0_orig, 3);
+		d0 = vec_sel(d0_orig, d4, vsel3);
+		sum30 += d0 * d;
+		sum31 += d1 * d;
+		sum32 += d2 * d;
+		sum33 += d3 * d;
+
+		d0 = d1;
+		d1 = d2;
+		d2 = d3;
+		d3 = d4;
+	}
+
+	sum0 += vec_perm(sum10, sum11, (vector unsigned char)vperm1);
+	sum1 += vec_perm(sum11, sum12, (vector unsigned char)vperm1);
+	sum2 += vec_perm(sum12, sum13, (vector unsigned char)vperm1);
+	sum3 += vec_perm(sum13, sum10, (vector unsigned char)vperm1);
+
+	sum0 += vec_perm(sum20, sum21, (vector unsigned char)vperm2);
+	sum1 += vec_perm(sum21, sum22, (vector unsigned char)vperm2);
+	sum2 += vec_perm(sum22, sum23, (vector unsigned char)vperm2);
+	sum3 += vec_perm(sum23, sum20, (vector unsigned char)vperm2);
+
+	sum0 += vec_perm(sum30, sum31, (vector unsigned char)vperm3);
+	sum1 += vec_perm(sum31, sum32, (vector unsigned char)vperm3);
+	sum2 += vec_perm(sum32, sum33, (vector unsigned char)vperm3);
+	sum3 += vec_perm(sum33, sum30, (vector unsigned char)vperm3);
+
+	for (; i <= limit; i++) {
+		vector float d;
+
+		d0 = vec_vsx_ld(0, data+i);
+		d1 = vec_vsx_ld(16, data+i);
+		d2 = vec_vsx_ld(32, data+i);
+		d3 = vec_vsx_ld(48, data+i);
+
+		d = vec_splat(d0, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+		sum2 += d2 * d;
+		sum3 += d3 * d;
+	}
+
+	vec_vsx_st(sum0, 0, autoc);
+	vec_vsx_st(sum1, 16, autoc);
+	vec_vsx_st(sum2, 32, autoc);
+	vec_vsx_st(sum3, 48, autoc);
+
+	for (; i < (long)data_len; i++) {
+		uint32_t coeff;
+
+		FLAC__real d = data[i];
+		for (coeff = 0; coeff < data_len - i; coeff++)
+			autoc[coeff] += d * data[i+coeff];
+	}
+}
+
+__attribute__((target("cpu=power9")))
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	long i;
+	long limit = (long)data_len - 12;
+	const FLAC__real *base;
+	vector float sum0 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum1 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum2 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum10 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum11 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum12 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum20 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum21 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum22 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum30 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum31 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum32 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float d0, d1, d2, d3;
+#if WORDS_BIGENDIAN
+	vector unsigned int vsel1 = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+	vector unsigned int vsel2 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vsel3 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vperm1 = { 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213 };
+	vector unsigned int vperm2 = { 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617 };
+	vector unsigned int vperm3 = { 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B };
+#else
+	vector unsigned int vsel1 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+	vector unsigned int vsel2 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+	vector unsigned int vsel3 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+	vector unsigned int vperm1 = { 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110 };
+	vector unsigned int vperm2 = { 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514 };
+	vector unsigned int vperm3 = { 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918 };
+#endif
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 12);
+	FLAC__ASSERT(lag <= data_len);
+
+	base = data;
+
+	d0 = vec_vsx_ld(0, base);
+	d1 = vec_vsx_ld(16, base);
+	d2 = vec_vsx_ld(32, base);
+
+	base += 12;
+
+	for (i = 0; i <= (limit-3); i += 4) {
+		vector float d, d0_orig = d0;
+
+		d3 = vec_vsx_ld(0, base);
+		base += 4;
+
+		d = vec_splat(d0_orig, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+		sum2 += d2 * d;
+
+		d = vec_splat(d0_orig, 1);
+		d0 = vec_sel(d0_orig, d3, vsel1);
+		sum10 += d0 * d;
+		sum11 += d1 * d;
+		sum12 += d2 * d;
+
+		d = vec_splat(d0_orig, 2);
+		d0 = vec_sel(d0_orig, d3, vsel2);
+		sum20 += d0 * d;
+		sum21 += d1 * d;
+		sum22 += d2 * d;
+
+		d = vec_splat(d0_orig, 3);
+		d0 = vec_sel(d0_orig, d3, vsel3);
+		sum30 += d0 * d;
+		sum31 += d1 * d;
+		sum32 += d2 * d;
+
+		d0 = d1;
+		d1 = d2;
+		d2 = d3;
+	}
+
+	sum0 += vec_perm(sum10, sum11, (vector unsigned char)vperm1);
+	sum1 += vec_perm(sum11, sum12, (vector unsigned char)vperm1);
+	sum2 += vec_perm(sum12, sum10, (vector unsigned char)vperm1);
+
+	sum0 += vec_perm(sum20, sum21, (vector unsigned char)vperm2);
+	sum1 += vec_perm(sum21, sum22, (vector unsigned char)vperm2);
+	sum2 += vec_perm(sum22, sum20, (vector unsigned char)vperm2);
+
+	sum0 += vec_perm(sum30, sum31, (vector unsigned char)vperm3);
+	sum1 += vec_perm(sum31, sum32, (vector unsigned char)vperm3);
+	sum2 += vec_perm(sum32, sum30, (vector unsigned char)vperm3);
+
+	for (; i <= limit; i++) {
+		vector float d;
+
+		d0 = vec_vsx_ld(0, data+i);
+		d1 = vec_vsx_ld(16, data+i);
+		d2 = vec_vsx_ld(32, data+i);
+
+		d = vec_splat(d0, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+		sum2 += d2 * d;
+	}
+
+	vec_vsx_st(sum0, 0, autoc);
+	vec_vsx_st(sum1, 16, autoc);
+	vec_vsx_st(sum2, 32, autoc);
+
+	for (; i < (long)data_len; i++) {
+		uint32_t coeff;
+
+		FLAC__real d = data[i];
+		for (coeff = 0; coeff < data_len - i; coeff++)
+			autoc[coeff] += d * data[i+coeff];
+	}
+}
+
+__attribute__((target("cpu=power9")))
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	long i;
+	long limit = (long)data_len - 8;
+	const FLAC__real *base;
+	vector float sum0 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum1 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum10 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum11 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum20 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum21 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum30 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum31 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float d0, d1, d2;
+#if WORDS_BIGENDIAN
+	vector unsigned int vsel1 = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+	vector unsigned int vsel2 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vsel3 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vperm1 = { 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213 };
+	vector unsigned int vperm2 = { 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617 };
+	vector unsigned int vperm3 = { 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B };
+#else
+	vector unsigned int vsel1 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+	vector unsigned int vsel2 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+	vector unsigned int vsel3 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+	vector unsigned int vperm1 = { 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110 };
+	vector unsigned int vperm2 = { 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514 };
+	vector unsigned int vperm3 = { 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918 };
+#endif
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 8);
+	FLAC__ASSERT(lag <= data_len);
+
+	base = data;
+
+	d0 = vec_vsx_ld(0, base);
+	d1 = vec_vsx_ld(16, base);
+
+	base += 8;
+
+	for (i = 0; i <= (limit-2); i += 4) {
+		vector float d, d0_orig = d0;
+
+		d2 = vec_vsx_ld(0, base);
+		base += 4;
+
+		d = vec_splat(d0_orig, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+
+		d = vec_splat(d0_orig, 1);
+		d0 = vec_sel(d0_orig, d2, vsel1);
+		sum10 += d0 * d;
+		sum11 += d1 * d;
+
+		d = vec_splat(d0_orig, 2);
+		d0 = vec_sel(d0_orig, d2, vsel2);
+		sum20 += d0 * d;
+		sum21 += d1 * d;
+
+		d = vec_splat(d0_orig, 3);
+		d0 = vec_sel(d0_orig, d2, vsel3);
+		sum30 += d0 * d;
+		sum31 += d1 * d;
+
+		d0 = d1;
+		d1 = d2;
+	}
+
+	sum0 += vec_perm(sum10, sum11, (vector unsigned char)vperm1);
+	sum1 += vec_perm(sum11, sum10, (vector unsigned char)vperm1);
+
+	sum0 += vec_perm(sum20, sum21, (vector unsigned char)vperm2);
+	sum1 += vec_perm(sum21, sum20, (vector unsigned char)vperm2);
+
+	sum0 += vec_perm(sum30, sum31, (vector unsigned char)vperm3);
+	sum1 += vec_perm(sum31, sum30, (vector unsigned char)vperm3);
+
+	for (; i <= limit; i++) {
+		vector float d;
+
+		d0 = vec_vsx_ld(0, data+i);
+		d1 = vec_vsx_ld(16, data+i);
+
+		d = vec_splat(d0, 0);
+		sum0 += d0 * d;
+		sum1 += d1 * d;
+	}
+
+	vec_vsx_st(sum0, 0, autoc);
+	vec_vsx_st(sum1, 16, autoc);
+
+	for (; i < (long)data_len; i++) {
+		uint32_t coeff;
+
+		FLAC__real d = data[i];
+		for (coeff = 0; coeff < data_len - i; coeff++)
+			autoc[coeff] += d * data[i+coeff];
+	}
+}
+
+__attribute__((target("cpu=power9")))
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	long i;
+	long limit = (long)data_len - 4;
+	const FLAC__real *base;
+	vector float sum0 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum10 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum20 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float sum30 = { 0.0f, 0.0f, 0.0f, 0.0f};
+	vector float d0, d1;
+#if WORDS_BIGENDIAN
+	vector unsigned int vsel1 = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+	vector unsigned int vsel2 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vsel3 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+	vector unsigned int vperm1 = { 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213 };
+	vector unsigned int vperm2 = { 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617 };
+	vector unsigned int vperm3 = { 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B };
+#else
+	vector unsigned int vsel1 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+	vector unsigned int vsel2 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+	vector unsigned int vsel3 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+	vector unsigned int vperm1 = { 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110 };
+	vector unsigned int vperm2 = { 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514 };
+	vector unsigned int vperm3 = { 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918 };
+#endif
+
+	(void) lag;
+	FLAC__ASSERT(lag <= 4);
+	FLAC__ASSERT(lag <= data_len);
+
+	base = data;
+
+	d0 = vec_vsx_ld(0, base);
+
+	base += 4;
+
+	for (i = 0; i <= (limit-1); i += 4) {
+		vector float d, d0_orig = d0;
+
+		d1 = vec_vsx_ld(0, base);
+		base += 4;
+
+		d = vec_splat(d0_orig, 0);
+		sum0 += d0 * d;
+
+		d = vec_splat(d0_orig, 1);
+		d0 = vec_sel(d0_orig, d1, vsel1);
+		sum10 += d0 * d;
+
+		d = vec_splat(d0_orig, 2);
+		d0 = vec_sel(d0_orig, d1, vsel2);
+		sum20 += d0 * d;
+
+		d = vec_splat(d0_orig, 3);
+		d0 = vec_sel(d0_orig, d1, vsel3);
+		sum30 += d0 * d;
+
+		d0 = d1;
+	}
+
+	sum0 += vec_perm(sum10, sum10, (vector unsigned char)vperm1);
+
+	sum0 += vec_perm(sum20, sum20, (vector unsigned char)vperm2);
+
+	sum0 += vec_perm(sum30, sum30, (vector unsigned char)vperm3);
+
+	for (; i <= limit; i++) {
+		vector float d;
+
+		d0 = vec_vsx_ld(0, data+i);
+
+		d = vec_splat(d0, 0);
+		sum0 += d0 * d;
+	}
+
+	vec_vsx_st(sum0, 0, autoc);
+
+	for (; i < (long)data_len; i++) {
+		uint32_t coeff;
+
+		FLAC__real d = data[i];
+		for (coeff = 0; coeff < data_len - i; coeff++)
+			autoc[coeff] += d * data[i+coeff];
+	}
+}
+#endif /* FLAC__HAS_TARGET_POWER9 */
+
+#endif /* FLAC__CPU_PPC64 && FLAC__USE_VSX */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/md5.c b/src/libFLAC/md5.c
new file mode 100644
index 0000000..09933d7
--- /dev/null
+++ b/src/libFLAC/md5.c
@@ -0,0 +1,517 @@
+#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/compat.h"
+#include "share/endswap.h"
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain.
+ */
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+	 (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
+{
+	register FLAC__uint32 a, b, c, d;
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#if WORDS_BIGENDIAN
+//@@@@@@ OPT: use bswap/intrinsics
+static void byteSwap(FLAC__uint32 *buf, uint32_t words)
+{
+	register FLAC__uint32 x;
+	do {
+		x = *buf;
+		x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);
+		*buf++ = (x >> 16) | (x << 16);
+	} while (--words);
+}
+static void byteSwapX16(FLAC__uint32 *buf)
+{
+	register FLAC__uint32 x;
+
+	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.
+ */
+static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, uint32_t len)
+{
+	FLAC__uint32 t;
+
+	/* Update byte count */
+
+	t = ctx->bytes[0];
+	if ((ctx->bytes[0] = t + len) < t)
+		ctx->bytes[1]++;	/* Carry from low to high */
+
+	t = 64 - (t & 0x3f);	/* Space available in ctx->in (at least 1) */
+	if (t > len) {
+		memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len);
+		return;
+	}
+	/* First chunk is an odd size */
+	memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t);
+	byteSwapX16(ctx->in);
+	FLAC__MD5Transform(ctx->buf, ctx->in);
+	buf += t;
+	len -= t;
+
+	/* Process data in 64-byte chunks */
+	while (len >= 64) {
+		memcpy(ctx->in, buf, 64);
+		byteSwapX16(ctx->in);
+		FLAC__MD5Transform(ctx->buf, ctx->in);
+		buf += 64;
+		len -= 64;
+	}
+
+	/* Handle any remaining bytes of data. */
+	memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void FLAC__MD5Init(FLAC__MD5Context *ctx)
+{
+	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.p8 = 0;
+	ctx->capacity = 0;
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx)
+{
+	int count = ctx->bytes[0] & 0x3f;	/* Number of bytes in ctx->in */
+	FLAC__byte *p = (FLAC__byte *)ctx->in + count;
+
+	/* Set the first char of padding to 0x80.  There is always room. */
+	*p++ = 0x80;
+
+	/* Bytes of padding needed to make 56 bytes (-8..55) */
+	count = 56 - 1 - count;
+
+	if (count < 0) {	/* Padding forces an extra block */
+		memset(p, 0, count + 8);
+		byteSwapX16(ctx->in);
+		FLAC__MD5Transform(ctx->buf, ctx->in);
+		p = (FLAC__byte *)ctx->in;
+		count = 56;
+	}
+	memset(p, 0, count);
+	byteSwap(ctx->in, 14);
+
+	/* Append length in bits and transform */
+	ctx->in[14] = ctx->bytes[0] << 3;
+	ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+	FLAC__MD5Transform(ctx->buf, ctx->in);
+
+	byteSwap(ctx->buf, 4);
+	memcpy(digest, ctx->buf, 16);
+	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[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample)
+{
+	FLAC__byte *buf_ = mbuf->p8;
+	FLAC__int16 *buf16 = mbuf->p16;
+	FLAC__int32 *buf32 = mbuf->p32;
+	FLAC__int32 a_word;
+	uint32_t 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[], uint32_t channels, uint32_t samples, uint32_t 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) {
+		if (0 == (ctx->internal_buf.p8 = safe_realloc_(ctx->internal_buf.p8, bytes_needed))) {
+			if (0 == (ctx->internal_buf.p8 = safe_malloc_(bytes_needed))) {
+				ctx->capacity = 0;
+				return false;
+			}
+		}
+		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;
+}
diff --git a/src/libFLAC/memory.c b/src/libFLAC/memory.c
new file mode 100644
index 0000000..4d320a4
--- /dev/null
+++ b/src/libFLAC/memory.c
@@ -0,0 +1,219 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "private/memory.h"
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "share/alloc.h"
+
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address)
+{
+	void *x;
+
+	FLAC__ASSERT(0 != aligned_address);
+
+#ifdef FLAC__ALIGN_MALLOC_DATA
+	/* align on 32-byte (256-bit) boundary */
+	x = safe_malloc_add_2op_(bytes, /*+*/31L);
+	*aligned_address = (void*)(((uintptr_t)x + 31L) & -32L);
+#else
+	x = safe_malloc_(bytes);
+	*aligned_address = x;
+#endif
+	return x;
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_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);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	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;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_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);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	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;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_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);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	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;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, uint32_t **unaligned_pointer, uint32_t **aligned_pointer)
+{
+	uint32_t *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		uint32_t *pa; /* aligned pointer */
+		void     *pv; /* aligned pointer alias */
+	} u;
+
+	FLAC__ASSERT(elements > 0);
+	FLAC__ASSERT(0 != unaligned_pointer);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	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;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+#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 *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);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	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;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*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);
+}
diff --git a/src/libFLAC/metadata_iterators.c b/src/libFLAC/metadata_iterators.c
new file mode 100644
index 0000000..17f25cd
--- /dev/null
+++ b/src/libFLAC/metadata_iterators.c
@@ -0,0 +1,3487 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#include "private/metadata.h"
+
+#include "FLAC/assert.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"
+
+/* 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
+ *
+ ***************************************************************************/
+
+static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);
+static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);
+static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes);
+static FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes);
+static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes);
+static FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes);
+
+static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
+static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t block_length);
+
+static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length);
+static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length);
+static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
+static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
+static FLAC__bool write_metadata_block_data_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, uint32_t block_length);
+
+static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last);
+static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
+
+static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
+
+static uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
+static uint32_t 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, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup);
+
+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);
+
+static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
+
+static FLAC__bool get_file_stats_(const char *filename, struct 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);
+
+static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
+
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+	size_t ret = fwrite(ptr, size, nmemb, stream);
+	if(!ferror(stream))
+		fflush(stream);
+	return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+/****************************************************************************
+ *
+ * Level 0 implementation
+ *
+ ***************************************************************************/
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__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__StreamMetadata *object;
+} level0_client_data;
+
+static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
+{
+	level0_client_data cd;
+	FLAC__StreamDecoder *decoder;
+
+	FLAC__ASSERT(0 != filename);
+
+	cd.got_error = false;
+	cd.object = 0;
+
+	decoder = FLAC__stream_decoder_new();
+
+	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__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 0;
+	}
+
+	(void)FLAC__stream_decoder_finish(decoder);
+	FLAC__stream_decoder_delete(decoder);
+
+	return cd.object;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
+{
+	FLAC__StreamMetadata *object;
+
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != streaminfo);
+
+	object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
+
+	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;
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != tags);
+
+	*tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	return 0 != *tags;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != cuesheet);
+
+	*cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
+
+	return 0 != *cuesheet;
+}
+
+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;
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+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;
+
+	/*
+	 * we assume we only get here when the one metadata block we were
+	 * looking for was passed to us
+	 */
+	if(!cd->got_error && 0 == cd->object) {
+		if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
+			cd->got_error = true;
+	}
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	level0_client_data *cd = (level0_client_data *)client_data;
+	(void)decoder;
+
+	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+		cd->got_error = true;
+}
+
+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, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t 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
+ *
+ ***************************************************************************/
+
+#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
+/* 1 for initial offset, +4 for our own personal use */
+
+struct FLAC__Metadata_SimpleIterator {
+	FILE *file;
+	char *filename, *tempfile_path_prefix;
+	struct flac_stat_s stats;
+	FLAC__bool has_stats;
+	FLAC__bool is_writable;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
+	FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */
+	uint32_t depth;
+	/* this is the metadata block header of the current block we are pointing to: */
+	FLAC__bool is_last;
+	FLAC__MetadataType type;
+	uint32_t length;
+};
+
+FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
+};
+
+
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
+{
+	FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
+
+	if(0 != iterator) {
+		iterator->file = 0;
+		iterator->filename = 0;
+		iterator->tempfile_path_prefix = 0;
+		iterator->has_stats = false;
+		iterator->is_writable = false;
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+		iterator->first_offset = iterator->offset[0] = -1;
+		iterator->depth = 0;
+	}
+
+	return iterator;
+}
+
+static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	if(0 != iterator->file) {
+		fclose(iterator->file);
+		iterator->file = 0;
+		if(iterator->has_stats)
+			set_file_stats_(iterator->filename, &iterator->stats);
+	}
+	if(0 != iterator->filename) {
+		free(iterator->filename);
+		iterator->filename = 0;
+	}
+	if(0 != iterator->tempfile_path_prefix) {
+		free(iterator->tempfile_path_prefix);
+		iterator->tempfile_path_prefix = 0;
+	}
+}
+
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	simple_iterator_free_guts_(iterator);
+	free(iterator);
+}
+
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+
+	FLAC__ASSERT(0 != iterator);
+
+	status = iterator->status;
+	iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+	return status;
+}
+
+static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
+{
+	uint32_t ret;
+
+	FLAC__ASSERT(0 != iterator);
+
+	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 = flac_fopen(iterator->filename, "rb"))) {
+				iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+				return false;
+			}
+		}
+		else {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+			return false;
+		}
+	}
+	else {
+		iterator->is_writable = true;
+	}
+
+	ret = seek_to_first_metadata_block_(iterator->file);
+	switch(ret) {
+		case 0:
+			iterator->depth = 0;
+			iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file);
+			return read_metadata_block_header_(iterator);
+		case 1:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		case 2:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		case 3:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
+			return false;
+		default:
+			FLAC__ASSERT(0);
+			return false;
+	}
+}
+
+#if 0
+@@@ If we decide to finish implementing this, put this comment back in metadata.h
+/*
+ * The 'tempfile_path_prefix' allows you to specify a directory where
+ * tempfiles should go.  Remember that if your metadata edits cause the
+ * FLAC file to grow, the entire file will have to be rewritten.  If
+ * 'tempfile_path_prefix' is NULL, the temp file will be written in the
+ * same directory as the original FLAC file.  This makes replacing the
+ * original with the tempfile fast but requires extra space in the same
+ * partition for the tempfile.  If space is a problem, you can pass a
+ * directory name belonging to a different partition in
+ * 'tempfile_path_prefix'.  Note that you should use the forward slash
+ * '/' as the directory separator.  A trailing slash is not needed; it
+ * will be added automatically.
+ */
+FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix);
+#endif
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
+{
+	const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'flac_rename(...)' for what it will take to finish implementing this */
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != filename);
+
+	simple_iterator_free_guts_(iterator);
+
+	if(!read_only && preserve_file_stats)
+		iterator->has_stats = get_file_stats_(filename, &iterator->stats);
+
+	if(0 == (iterator->filename = strdup(filename))) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	return simple_iterator_prime_input_(iterator, read_only);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	return iterator->is_writable;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	if(iterator->is_last)
+		return false;
+
+	if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	iterator->offset[iterator->depth] = ftello(iterator->file);
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__off_t this_offset;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	if(iterator->offset[iterator->depth] == iterator->first_offset)
+		return false;
+
+	if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+	this_offset = iterator->first_offset;
+	if(!read_metadata_block_header_(iterator))
+		return false;
+
+	/* we ignore any error from 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 = ftello(iterator->file);
+		if(!read_metadata_block_header_(iterator))
+			return false;
+	}
+
+	iterator->offset[iterator->depth] = this_offset;
+
+	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);
+	FLAC__ASSERT(0 != iterator->file);
+
+	return iterator->type;
+}
+
+/*@@@@add to tests*/
+FLAC_API uint32_t 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 uint32_t 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);
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	if(0 != block) {
+		block->is_last = iterator->is_last;
+		block->length = iterator->length;
+
+		if(!read_metadata_block_data_(iterator, block)) {
+			FLAC__metadata_object_delete(block);
+			return 0;
+		}
+
+		/* back up to the beginning of the block data to stay consistent */
+		if(0 != 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;
+		}
+	}
+	else
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	return block;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+	FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];)
+	FLAC__bool ret;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+	FLAC__ASSERT(0 != block);
+
+	if(!iterator->is_writable) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+		return false;
+	}
+
+	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		if(iterator->type != block->type) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+			return false;
+		}
+	}
+
+	block->is_last = iterator->is_last;
+
+	if(iterator->length == block->length)
+		return write_metadata_block_stationary_(iterator, block);
+	else if(iterator->length > block->length) {
+		if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
+			ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
+			FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+			FLAC__ASSERT(!ret || 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 || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+	}
+	else /* iterator->length < block->length */ {
+		uint32_t padding_leftover = 0;
+		FLAC__bool padding_is_last = false;
+		if(use_padding) {
+			/* first see if we can even use padding */
+			if(iterator->is_last) {
+				use_padding = false;
+			}
+			else {
+				const uint32_t extra_padding_bytes_required = block->length - iterator->length;
+				simple_iterator_push_(iterator);
+				if(!FLAC__metadata_simple_iterator_next(iterator)) {
+					(void)simple_iterator_pop_(iterator);
+					return false;
+				}
+				if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+					use_padding = false;
+				}
+				else {
+					if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
+						padding_leftover = 0;
+						block->is_last = iterator->is_last;
+					}
+					else if(iterator->length < extra_padding_bytes_required)
+						use_padding = false;
+					else {
+						padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
+						padding_is_last = iterator->is_last;
+						block->is_last = false;
+					}
+				}
+				if(!simple_iterator_pop_(iterator))
+					return false;
+			}
+		}
+		if(use_padding) {
+			if(padding_leftover == 0) {
+				ret = write_metadata_block_stationary_(iterator, block);
+				FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+				FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+				return ret;
+			}
+			else {
+				FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
+				ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+				FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+				FLAC__ASSERT(!ret || 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 || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+	uint32_t padding_leftover = 0;
+	FLAC__bool padding_is_last = false;
+
+	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);
+	FLAC__ASSERT(0 != iterator->file);
+	FLAC__ASSERT(0 != block);
+
+	if(!iterator->is_writable) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+		return false;
+	}
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+		return false;
+	}
+
+	block->is_last = iterator->is_last;
+
+	if(use_padding) {
+		/* first see if we can even use padding */
+		if(iterator->is_last) {
+			use_padding = false;
+		}
+		else {
+			simple_iterator_push_(iterator);
+			if(!FLAC__metadata_simple_iterator_next(iterator)) {
+				(void)simple_iterator_pop_(iterator);
+				return false;
+			}
+			if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+				use_padding = false;
+			}
+			else {
+				if(iterator->length == block->length) {
+					padding_leftover = 0;
+					block->is_last = iterator->is_last;
+				}
+				else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
+					use_padding = false;
+				else {
+					padding_leftover = iterator->length - block->length;
+					padding_is_last = iterator->is_last;
+					block->is_last = false;
+				}
+			}
+			if(!simple_iterator_pop_(iterator))
+				return false;
+		}
+	}
+	if(use_padding) {
+		/* move to the next block, which is suitable padding */
+		if(!FLAC__metadata_simple_iterator_next(iterator))
+			return false;
+		if(padding_leftover == 0) {
+			ret = write_metadata_block_stationary_(iterator, block);
+			FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+			FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+		else {
+			FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
+			ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+			FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+			FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+	}
+	else {
+		ret = rewrite_whole_file_(iterator, block, /*append=*/true);
+		FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+		FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+		return ret;
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
+{
+	FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];)
+	FLAC__bool ret;
+
+	if(!iterator->is_writable) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+		return false;
+	}
+
+	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+		return false;
+	}
+
+	if(use_padding) {
+		FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+		if(0 == padding) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		padding->length = iterator->length;
+		if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
+			FLAC__metadata_object_delete(padding);
+			return false;
+		}
+		FLAC__metadata_object_delete(padding);
+		if(!FLAC__metadata_simple_iterator_prev(iterator))
+			return false;
+		FLAC__ASSERT(iterator->offset[iterator->depth] + (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] + (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;
+	}
+}
+
+
+
+/****************************************************************************
+ *
+ * Level 2 implementation
+ *
+ ***************************************************************************/
+
+
+typedef struct FLAC__Metadata_Node {
+	FLAC__StreamMetadata *data;
+	struct FLAC__Metadata_Node *prev, *next;
+} FLAC__Metadata_Node;
+
+struct FLAC__Metadata_Chain {
+	char *filename; /* will be NULL if using callbacks */
+	FLAC__bool is_ogg;
+	FLAC__Metadata_Node *head;
+	FLAC__Metadata_Node *tail;
+	uint32_t nodes;
+	FLAC__Metadata_ChainStatus status;
+	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.
+	 */
+	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 {
+	FLAC__Metadata_Chain *chain;
+	FLAC__Metadata_Node *current;
+};
+
+FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
+	"FLAC__METADATA_CHAIN_STATUS_OK",
+	"FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
+	"FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
+	"FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
+	"FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
+	"FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
+	"FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
+	"FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
+	"FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
+};
+
+
+static FLAC__Metadata_Node *node_new_(void)
+{
+	return calloc(1, sizeof(FLAC__Metadata_Node));
+}
+
+static void node_delete_(FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != node);
+	if(0 != node->data)
+		FLAC__metadata_object_delete(node->data);
+	free(node);
+}
+
+static void chain_init_(FLAC__Metadata_Chain *chain)
+{
+	FLAC__ASSERT(0 != chain);
+
+	chain->filename = 0;
+	chain->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)
+{
+	FLAC__Metadata_Node *node, *next;
+
+	FLAC__ASSERT(0 != chain);
+
+	for(node = chain->head; node; ) {
+		next = node->next;
+		node_delete_(node);
+		node = next;
+	}
+
+	if(0 != chain->filename)
+		free(chain->filename);
+
+	chain_init_(chain);
+}
+
+static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != node);
+	FLAC__ASSERT(0 != node->data);
+
+	node->next = node->prev = 0;
+	node->data->is_last = true;
+	if(0 != chain->tail)
+		chain->tail->data->is_last = false;
+
+	if(0 == chain->head)
+		chain->head = node;
+	else {
+		FLAC__ASSERT(0 != chain->tail);
+		chain->tail->next = node;
+		node->prev = chain->tail;
+	}
+	chain->tail = node;
+	chain->nodes++;
+}
+
+static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != node);
+
+	if(node == chain->head)
+		chain->head = node->next;
+	else
+		node->prev->next = node->next;
+
+	if(node == chain->tail)
+		chain->tail = node->prev;
+	else
+		node->next->prev = node->prev;
+
+	if(0 != chain->tail)
+		chain->tail->data->is_last = true;
+
+	chain->nodes--;
+}
+
+static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	chain_remove_node_(chain, node);
+	node_delete_(node);
+}
+
+static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
+{
+	const FLAC__Metadata_Node *node;
+	FLAC__off_t length = 0;
+	for(node = chain->head; node; node = node->next)
+		length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+	return length;
+}
+
+static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != node);
+	FLAC__ASSERT(0 != node->data);
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != iterator->chain);
+	FLAC__ASSERT(0 != iterator->chain->head);
+	FLAC__ASSERT(0 != iterator->chain->tail);
+
+	node->data->is_last = false;
+
+	node->prev = iterator->current->prev;
+	node->next = iterator->current;
+
+	if(0 == node->prev)
+		iterator->chain->head = node;
+	else
+		node->prev->next = node;
+
+	iterator->current->prev = node;
+
+	iterator->chain->nodes++;
+}
+
+static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != node);
+	FLAC__ASSERT(0 != node->data);
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != iterator->chain);
+	FLAC__ASSERT(0 != iterator->chain->head);
+	FLAC__ASSERT(0 != iterator->chain->tail);
+
+	iterator->current->data->is_last = false;
+
+	node->prev = iterator->current;
+	node->next = iterator->current->next;
+
+	if(0 == node->next)
+		iterator->chain->tail = node;
+	else
+		node->next->prev = node;
+
+	node->prev->next = node;
+
+	iterator->chain->tail->data->is_last = true;
+
+	iterator->chain->nodes++;
+}
+
+/* return true iff node and node->next are both padding */
+static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
+		const uint32_t growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
+		node->data->length += growth; /* new block size can be greater than max metadata block size, but it'll be fixed later in chain_prepare_for_write_() */
+
+		chain_delete_node_(chain, node->next);
+		return true;
+	}
+	else
+		return false;
+}
+
+/* Returns the new length of the chain, or 0 if there was an error. */
+/* WATCHOUT: This can get called multiple times before a write, so
+ * it should still work when this happens.
+ */
+/* WATCHOUT: Make sure to also update the logic in
+ * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
+ */
+static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+	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 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__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))) {
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return 0;
+			}
+			padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length);
+			if(0 == (node = node_new_())) {
+				FLAC__metadata_object_delete(padding);
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return 0;
+			}
+			node->data = padding;
+			chain_append_node_(chain, node);
+			current_length = chain_calculate_length_(chain);
+			FLAC__ASSERT(current_length == chain->initial_length);
+		}
+		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+		else if(current_length > chain->initial_length) {
+			const 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((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((FLAC__off_t)chain->tail->data->length >= delta) {
+					chain->tail->data->length -= delta;
+					current_length -= delta;
+					FLAC__ASSERT(current_length == chain->initial_length);
+				}
+			}
+		}
+	}
+
+	/* check sizes of all metadata blocks; reduce padding size if necessary */
+	{
+		FLAC__Metadata_Node *node;
+		for (node = chain->head; node; node = node->next) {
+			if(node->data->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
+				if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+					node->data->length = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+					current_length = chain_calculate_length_(chain);
+				} else {
+					chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+					return 0;
+				}
+			}
+		}
+	}
+
+	return current_length;
+}
+
+static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+
+	/* we assume we're already at the beginning of the file */
+
+	switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
+		case 0:
+			break;
+		case 1:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		case 2:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+			return false;
+		case 3:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+			return false;
+		default:
+			FLAC__ASSERT(0);
+			return false;
+	}
+
+	{
+		FLAC__int64 pos = tell_cb(handle);
+		if(pos < 0) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		}
+		chain->first_offset = (FLAC__off_t)pos;
+	}
+
+	{
+		FLAC__bool is_last;
+		FLAC__MetadataType type;
+		uint32_t length;
+
+		do {
+			node = node_new_();
+			if(0 == node) {
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+
+			if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
+				node_delete_(node);
+				chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+				return false;
+			}
+
+			node->data = FLAC__metadata_object_new(type);
+			if(0 == node->data) {
+				node_delete_(node);
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+
+			node->data->is_last = is_last;
+			node->data->length = length;
+
+			chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
+			if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+				node_delete_(node);
+				return false;
+			}
+			chain_append_node_(chain, node);
+		} while(!is_last);
+	}
+
+	{
+		FLAC__int64 pos = tell_cb(handle);
+		if(pos < 0) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		}
+		chain->last_offset = (FLAC__off_t)pos;
+	}
+
+	chain->initial_length = chain_calculate_length_(chain);
+
+	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;
+
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != chain->head);
+
+	if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+		if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+	return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
+{
+	FILE *file;
+	FLAC__bool ret;
+
+	FLAC__ASSERT(0 != chain->filename);
+
+	if(0 == (file = flac_fopen(chain->filename, "r+b"))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	/* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
+	ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
+
+	fclose(file);
+
+	return ret;
+}
+
+static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
+{
+	FILE *f, *tempfile = NULL;
+	char *tempfilename;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != chain->filename);
+	FLAC__ASSERT(0 != chain->head);
+
+	/* copy the file prefix (data up to first metadata block */
+	if(0 == (f = 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);
+		goto err;
+	}
+	if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
+		chain->status = get_equivalent_status_(status);
+		goto err;
+	}
+
+	/* write the metadata */
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_(tempfile, &status, node->data)) {
+			chain->status = get_equivalent_status_(status);
+			goto err;
+		}
+		if(!write_metadata_block_data_(tempfile, &status, node->data)) {
+			chain->status = get_equivalent_status_(status);
+			goto err;
+		}
+	}
+	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+	/* copy the file postfix (everything after the metadata) */
+	if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		goto err;
+	}
+	if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
+		chain->status = get_equivalent_status_(status);
+		goto err;
+	}
+
+	/* move the tempfile on top of the original */
+	(void)fclose(f);
+	if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
+		return false;
+
+	return true;
+
+err:
+	(void)fclose(f);
+	cleanup_tempfile_(&tempfile, &tempfilename);
+	return false;
+}
+
+/* assumes 'handle' is already at beginning of file */
+static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 == chain->filename);
+	FLAC__ASSERT(0 != chain->head);
+
+	/* copy the file prefix (data up to first metadata block */
+	if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
+		chain->status = get_equivalent_status_(status);
+		return false;
+	}
+
+	/* write the metadata */
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+		if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+	/* copy the file postfix (everything after the metadata) */
+	if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
+		chain->status = get_equivalent_status_(status);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
+{
+	FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain));
+
+	if(0 != chain)
+		chain_init_(chain);
+
+	return chain;
+}
+
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
+{
+	FLAC__ASSERT(0 != chain);
+
+	chain_clear_(chain);
+
+	free(chain);
+}
+
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_ChainStatus status;
+
+	FLAC__ASSERT(0 != chain);
+
+	status = chain->status;
+	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+	return status;
+}
+
+static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
+{
+	FILE *file;
+	FLAC__bool ret;
+
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != filename);
+
+	chain_clear_(chain);
+
+	if(0 == (chain->filename = strdup(filename))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	chain->is_ogg = is_ogg;
+
+	if(0 == (file = flac_fopen(filename, "rb"))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	/* 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);
+
+	return ret;
+}
+
+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);
+
+	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	chain->is_ogg = is_ogg;
+
+	/* rewind */
+	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	/* 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 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);
+}
+
+typedef enum {
+	LBS_NONE = 0,
+	LBS_SIZE_CHANGED,
+	LBS_BLOCK_ADDED,
+	LBS_BLOCK_REMOVED
+} LastBlockState;
+
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+	/* This does all the same checks that are in chain_prepare_for_write_()
+	 * but doesn't actually alter the chain.  Make sure to update the logic
+	 * here if chain_prepare_for_write_() changes.
+	 */
+	FLAC__off_t current_length;
+	LastBlockState lbs_state = LBS_NONE;
+	uint32_t lbs_size = 0;
+
+	FLAC__ASSERT(0 != chain);
+
+	current_length = chain_calculate_length_(chain);
+
+	if(use_padding) {
+		const FLAC__Metadata_Node * const node = chain->tail;
+		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
+		if(current_length < chain->initial_length && node->data->type == FLAC__METADATA_TYPE_PADDING) {
+			lbs_state = LBS_SIZE_CHANGED;
+			lbs_size = node->data->length + (chain->initial_length - current_length);
+		}
+		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+		else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+			lbs_state = LBS_BLOCK_ADDED;
+			lbs_size = chain->initial_length - (current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+		}
+		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+		else if(current_length > chain->initial_length) {
+			const FLAC__off_t delta = current_length - chain->initial_length;
+			if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+				/* if the delta is exactly the size of the last padding block, remove the padding block */
+				if((FLAC__off_t)node->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+					lbs_state = LBS_BLOCK_REMOVED;
+					lbs_size = 0;
+				}
+				/* if there is at least 'delta' bytes of padding, trim the padding down */
+				else if((FLAC__off_t)node->data->length >= delta) {
+					lbs_state = LBS_SIZE_CHANGED;
+					lbs_size = node->data->length - delta;
+				}
+			}
+		}
+	}
+
+	current_length = 0;
+	/* check sizes of all metadata blocks; reduce padding size if necessary */
+	{
+		const FLAC__Metadata_Node *node;
+		for(node = chain->head; node; node = node->next) {
+			uint32_t block_len = node->data->length;
+			if(node == chain->tail) {
+				if(lbs_state == LBS_BLOCK_REMOVED)
+					continue;
+				else if(lbs_state == LBS_SIZE_CHANGED)
+					block_len = lbs_size;
+			}
+			if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
+				if(node->data->type == FLAC__METADATA_TYPE_PADDING)
+					block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+				else
+					return false /* the return value doesn't matter */;
+			}
+			current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
+		}
+
+		if(lbs_state == LBS_BLOCK_ADDED) {
+			/* test added padding block */
+			uint32_t block_len = lbs_size;
+			if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+				block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+			current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
+		}
+	}
+
+	return (current_length != chain->initial_length);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
+{
+	struct flac_stat_s stats;
+	const char *tempfile_path_prefix = 0;
+	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;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	if(preserve_file_stats)
+		get_file_stats_(chain->filename, &stats);
+
+	if(current_length == chain->initial_length) {
+		if(!chain_rewrite_metadata_in_place_(chain))
+			return false;
+	}
+	else {
+		if(!chain_rewrite_file_(chain, tempfile_path_prefix))
+			return false;
+
+		/* recompute lengths and offsets */
+		{
+			const FLAC__Metadata_Node *node;
+			chain->initial_length = current_length;
+			chain->last_offset = chain->first_offset;
+			for(node = chain->head; node; node = node->next)
+				chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+		}
+	}
+
+	if(preserve_file_stats)
+		set_file_stats_(chain->filename, &stats);
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+	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;
+	}
+
+	if (0 == callbacks.write || 0 == callbacks.seek) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+		return false;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	FLAC__ASSERT(current_length == chain->initial_length);
+
+	return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks)
+{
+	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;
+	}
+
+	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+	if (0 == temp_callbacks.write) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+		return false;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	FLAC__ASSERT(current_length != chain->initial_length);
+
+	/* rewind */
+	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
+		return false;
+
+	/* recompute lengths and offsets */
+	{
+		const FLAC__Metadata_Node *node;
+		chain->initial_length = current_length;
+		chain->last_offset = chain->first_offset;
+		for(node = chain->head; node; node = node->next)
+			chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+	}
+
+	return true;
+}
+
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+
+	for(node = chain->head; node; ) {
+		if(!chain_merge_adjacent_padding_(chain, node))
+			node = node->next;
+	}
+}
+
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_Node *node, *save;
+	uint32_t i;
+
+	FLAC__ASSERT(0 != chain);
+
+	/*
+	 * Don't try and be too smart... this simple algo is good enough for
+	 * the small number of nodes that we deal with.
+	 */
+	for(i = 0, node = chain->head; i < chain->nodes; i++) {
+		if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+			save = node->next;
+			chain_remove_node_(chain, node);
+			chain_append_node_(chain, node);
+			node = save;
+		}
+		else {
+			node = node->next;
+		}
+	}
+
+	FLAC__metadata_chain_merge_padding(chain);
+}
+
+
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
+{
+	FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iterator));
+
+	/* calloc() implies:
+		iterator->current = 0;
+		iterator->chain = 0;
+	*/
+
+	return iterator;
+}
+
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	free(iterator);
+}
+
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != chain->head);
+
+	iterator->chain = chain;
+	iterator->current = chain->head;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	if(0 == iterator->current || 0 == iterator->current->next)
+		return false;
+
+	iterator->current = iterator->current->next;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	if(0 == iterator->current || 0 == iterator->current->prev)
+		return false;
+
+	iterator->current = iterator->current->prev;
+	return true;
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != iterator->current->data);
+
+	return iterator->current->data->type;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+
+	return iterator->current->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != block);
+	return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
+{
+	FLAC__Metadata_Node *save;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+
+	if(0 == iterator->current->prev) {
+		FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
+		return false;
+	}
+
+	save = iterator->current->prev;
+
+	if(replace_with_padding) {
+		FLAC__metadata_object_delete_data(iterator->current->data);
+		iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
+	}
+	else {
+		chain_delete_node_(iterator->chain, iterator->current);
+	}
+
+	iterator->current = save;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != block);
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+		return false;
+
+	if(0 == iterator->current->prev) {
+		FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
+		return false;
+	}
+
+	if(0 == (node = node_new_()))
+		return false;
+
+	node->data = block;
+	iterator_insert_node_(iterator, node);
+	iterator->current = node;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != block);
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+		return false;
+
+	if(0 == (node = node_new_()))
+		return false;
+
+	node->data = block;
+	iterator_insert_node_after_(iterator, node);
+	iterator->current = node;
+	return true;
+}
+
+
+/****************************************************************************
+ *
+ * Local function definitions
+ *
+ ***************************************************************************/
+
+void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes)
+{
+	uint32_t i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++) {
+		*(--b) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes)
+{
+	uint32_t i;
+
+	for(i = 0; i < bytes; i++) {
+		*(b++) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes)
+{
+	uint32_t i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++) {
+		*(--b) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes)
+{
+	FLAC__uint32 ret = 0;
+	uint32_t i;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint32)(*b++);
+
+	return ret;
+}
+
+FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes)
+{
+	FLAC__uint32 ret = 0;
+	uint32_t i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint32)(*--b);
+
+	return ret;
+}
+
+FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes)
+{
+	FLAC__uint64 ret = 0;
+	uint32_t i;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint64)(*b++);
+
+	return ret;
+}
+
+FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
+
+	return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+}
+
+FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length)
+{
+	FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+	if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+		return false;
+
+	*is_last = raw_header[0] & 0x80? true : false;
+	*type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
+	*length = unpack_uint32_(raw_header + 1, 3);
+
+	/* Note that we don't check:
+	 *    if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
+	 * we just will read in an opaque block
+	 */
+
+	return true;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block)
+{
+	switch(block->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length);
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, 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);
+	}
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
+
+	if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	b = buffer;
+
+	/* we are using hardcoded numbers for simplicity but we should
+	 * probably eventually write a bit-level unpacker and use the
+	 * _STREAMINFO_ constants.
+	 */
+	block->min_blocksize = unpack_uint32_(b, 2); b += 2;
+	block->max_blocksize = unpack_uint32_(b, 2); b += 2;
+	block->min_framesize = unpack_uint32_(b, 3); b += 3;
+	block->max_framesize = unpack_uint32_(b, 3); b += 3;
+	block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((uint32_t)(b[2] & 0xf0) >> 4);
+	block->channels = (uint32_t)((b[2] & 0x0e) >> 1) + 1;
+	block->bits_per_sample = ((((uint32_t)(b[2] & 0x01)) << 4) | (((uint32_t)(b[3] & 0xf0)) >> 4)) + 1;
+	block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
+	memcpy(block->md5sum, b+8, 16);
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length)
+{
+	(void)block; /* nothing to do; we don't care about reading the padding bytes */
+
+	if(0 != seek_cb(handle, block_length, SEEK_CUR))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length)
+{
+	const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+	if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	if(block_length < id_bytes)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	block_length -= id_bytes;
+
+	if(block_length == 0) {
+		block->data = 0;
+	}
+	else {
+		if(0 == (block->data = malloc(block_length)))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+		if(read_cb(block->data, 1, block_length, handle) != block_length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length)
+{
+	uint32_t i;
+	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+	FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0);
+
+	block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+	if(block->num_points == 0)
+		block->points = 0;
+	else if(0 == (block->points = 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++) {
+		if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		/* some MAGIC NUMBERs here */
+		block->points[i].sample_number = unpack_uint64_(buffer, 8);
+		block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
+		block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length)
+{
+	const uint32_t 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 == 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);
+
+	if(entry->length == 0) {
+		entry->entry = 0;
+	}
+	else {
+		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__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length)
+{
+	uint32_t i;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const uint32_t 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 == sizeof(buffer));
+
+	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);
+
+	if(block->num_comments == 0) {
+		block->comments = 0;
+	}
+	else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+		block->num_comments = 0;
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+	}
+
+	for(i = 0; i < block->num_comments; i++) {
+		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;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
+{
+	uint32_t i, len;
+	FLAC__byte buffer[32]; /* asserted below that this is big enough */
+
+	FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->offset = unpack_uint64_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+	if(read_cb(track->isrc, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
+	len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1);
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1);
+	track->type = buffer[0] >> 7;
+	track->pre_emphasis = (buffer[0] >> 6) & 1;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
+
+	if(track->num_indices == 0) {
+		track->indices = 0;
+	}
+	else if(0 == (track->indices = calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < track->num_indices; i++) {
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		track->indices[i].offset = unpack_uint64_(buffer, len);
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block)
+{
+	uint32_t i, len;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
+
+	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer));
+	FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer));
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+	if(read_cb(block->media_catalog_number, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->lead_in = unpack_uint64_(buffer, len);
+
+	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
+	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->is_cd = buffer[0]&0x80? true : false;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->num_tracks = unpack_uint32_(buffer, len);
+
+	if(block->num_tracks == 0) {
+		block->tracks = 0;
+	}
+	else if(0 == (block->tracks = calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < block->num_tracks; i++) {
+		if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
+			return status;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+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, uint32_t block_length)
+{
+	if(block_length == 0) {
+		block->data = 0;
+	}
+	else {
+		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)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != file);
+	FLAC__ASSERT(0 != status);
+
+	if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != file);
+	FLAC__ASSERT(0 != status);
+
+	if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+		return true;
+	}
+	else {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+		return false;
+	}
+}
+
+FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+	FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+	/* double protection */
+	if(block->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+		return false;
+
+	buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
+	pack_uint32_(block->length, buffer + 1, 3);
+
+	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != block);
+
+	switch(block->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
+		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);
+	}
+}
+
+FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
+	const uint32_t channels1 = block->channels - 1;
+	const uint32_t bps1 = block->bits_per_sample - 1;
+
+	/* we are using hardcoded numbers for simplicity but we should
+	 * probably eventually write a bit-level packer and use the
+	 * _STREAMINFO_ constants.
+	 */
+	pack_uint32_(block->min_blocksize, buffer, 2);
+	pack_uint32_(block->max_blocksize, buffer+2, 2);
+	pack_uint32_(block->min_framesize, buffer+4, 3);
+	pack_uint32_(block->max_framesize, buffer+7, 3);
+	buffer[10] = (block->sample_rate >> 12) & 0xff;
+	buffer[11] = (block->sample_rate >> 4) & 0xff;
+	buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4);
+	buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
+	pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
+	memcpy(buffer+18, block->md5sum, 16);
+
+	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length)
+{
+	uint32_t i, n = block_length;
+	FLAC__byte buffer[1024];
+
+	(void)block;
+
+	memset(buffer, 0, 1024);
+
+	for(i = 0; i < n/1024; i++)
+		if(write_cb(buffer, 1, 1024, handle) != 1024)
+			return false;
+
+	n %= 1024;
+
+	if(write_cb(buffer, 1, n, handle) != n)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length)
+{
+	const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+	if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
+		return false;
+
+	block_length -= id_bytes;
+
+	if(write_cb(block->data, 1, block_length, handle) != block_length)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
+{
+	uint32_t i;
+	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+	for(i = 0; i < block->num_points; i++) {
+		/* some MAGIC NUMBERs here */
+		pack_uint64_(block->points[i].sample_number, buffer, 8);
+		pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
+		pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
+		if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
+{
+	uint32_t i;
+	const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+	const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	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)
+		return false;
+	if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
+		return false;
+
+	pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
+	if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+		return false;
+
+	for(i = 0; i < block->num_comments; i++) {
+		pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
+		if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+			return false;
+		if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
+{
+	uint32_t i, j, len;
+	FLAC__byte buffer[1024]; /* asserted below that this is big enough */
+
+	FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+	if(write_cb(block->media_catalog_number, 1, len, handle) != len)
+		return false;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+	pack_uint64_(block->lead_in, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
+	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+	memset(buffer, 0, len);
+	if(block->is_cd)
+		buffer[0] |= 0x80;
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+	pack_uint32_(block->num_tracks, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	for(i = 0; i < block->num_tracks; i++) {
+		FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+		pack_uint64_(track->offset, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+		pack_uint32_(track->number, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+		if(write_cb(track->isrc, 1, len, handle) != len)
+			return false;
+
+		FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
+		len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+		memset(buffer, 0, len);
+		buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+		pack_uint32_(track->num_indices, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		for(j = 0; j < track->num_indices; j++) {
+			FLAC__StreamMetadata_CueSheet_Index *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_(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_(indx->number, buffer, len);
+			if(write_cb(buffer, 1, len, handle) != len)
+				return false;
+
+			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
+			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+			memset(buffer, 0, len);
+			if(write_cb(buffer, 1, len, handle) != len)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
+{
+	uint32_t 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, uint32_t block_length)
+{
+	if(write_cb(block->data, 1, block_length, handle) != block_length)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
+{
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last)
+{
+	FLAC__StreamMetadata *padding;
+
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	block->is_last = false;
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	padding->is_last = padding_is_last;
+	padding->length = padding_length;
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
+		FLAC__metadata_object_delete(padding);
+		return false;
+	}
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
+		FLAC__metadata_object_delete(padding);
+		return false;
+	}
+
+	FLAC__metadata_object_delete(padding);
+
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
+{
+	FILE *tempfile = NULL;
+	char *tempfilename = NULL;
+	int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
+	FLAC__off_t fixup_is_last_flag_offset = -1;
+
+	FLAC__ASSERT(0 != block || append == false);
+
+	if(iterator->is_last) {
+		if(append) {
+			fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
+			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+		}
+		else if(0 == block) {
+			simple_iterator_push_(iterator);
+			if(!FLAC__metadata_simple_iterator_prev(iterator)) {
+				(void)simple_iterator_pop_(iterator);
+				return false;
+			}
+			fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
+			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+			if(!simple_iterator_pop_(iterator))
+				return false;
+		}
+	}
+
+	if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
+		return false;
+
+	if(0 != block) {
+		if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
+			cleanup_tempfile_(&tempfile, &tempfilename);
+			return false;
+		}
+
+		if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
+			cleanup_tempfile_(&tempfile, &tempfilename);
+			return false;
+		}
+	}
+
+	if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
+		return false;
+
+	if(append)
+		return FLAC__metadata_simple_iterator_next(iterator);
+
+	return true;
+}
+
+void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
+	iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
+	iterator->depth++;
+}
+
+FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(iterator->depth > 0);
+	iterator->depth--;
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+/* return meanings:
+ * 0: ok
+ * 1: read error
+ * 2: seek error
+ * 3: not a FLAC file
+ */
+uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb)
+{
+	FLAC__byte buffer[4];
+	size_t n;
+	uint32_t i;
+
+	FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer));
+
+	/* skip any id3v2 tag */
+	errno = 0;
+	n = read_cb(buffer, 1, 4, handle);
+	if(errno)
+		return 1;
+	else if(n != 4)
+		return 3;
+	else if(0 == memcmp(buffer, "ID3", 3)) {
+		uint32_t tag_length = 0;
+
+		/* skip to the tag length */
+		if(seek_cb(handle, 2, SEEK_CUR) < 0)
+			return 2;
+
+		/* read the length */
+		for(i = 0; i < 4; i++) {
+			if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80)
+				return 1;
+			tag_length <<= 7;
+			tag_length |= (buffer[0] & 0x7f);
+		}
+
+		/* skip the rest of the tag */
+		if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
+			return 2;
+
+		/* read the stream sync code */
+		errno = 0;
+		n = read_cb(buffer, 1, 4, handle);
+		if(errno)
+			return 1;
+		else if(n != 4)
+			return 3;
+	}
+
+	/* check for the fLaC signature */
+	if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
+		return 0;
+	else
+		return 3;
+}
+
+uint32_t seek_to_first_metadata_block_(FILE *f)
+{
+	return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_);
+}
+
+FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
+{
+	const 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 != fseeko(iterator->file, 0, SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+	if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup)
+{
+	FLAC__off_t save_offset = iterator->offset[iterator->depth];
+	FLAC__ASSERT(0 != *tempfile);
+
+	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;
+	}
+	if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+
+	if(fixup_is_last_code != 0) {
+		/*
+		 * if code == 1, it means a block was appended to the end so
+		 *   we have to clear the is_last flag of the previous block
+		 * if code == -1, it means the last block was deleted so
+		 *   we have to set the is_last flag of the previous block
+		 */
+		/* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
+		FLAC__byte x;
+		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		}
+		if(fread(&x, 1, 1, *tempfile) != 1) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(fixup_is_last_code > 0) {
+			FLAC__ASSERT(x & 0x80);
+			x &= 0x7f;
+		}
+		else {
+			FLAC__ASSERT(!(x & 0x80));
+			x |= 0x80;
+		}
+		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		}
+		if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	(void)fclose(iterator->file);
+
+	if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
+		return false;
+
+	if(iterator->has_stats)
+		set_file_stats_(iterator->filename, &iterator->stats);
+
+	if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
+		return false;
+	if(backup) {
+		while(iterator->offset[iterator->depth] + (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;
+	}
+	else {
+		/* move the iterator to it's original block faster by faking a push, then doing a pop_ */
+		FLAC__ASSERT(iterator->depth == 0);
+		iterator->offset[0] = save_offset;
+		iterator->depth++;
+		return simple_iterator_pop_(iterator);
+	}
+}
+
+FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	FLAC__ASSERT(bytes >= 0);
+	while(bytes > 0) {
+		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;
+		}
+		if(local__fwrite(buffer, 1, n, tempfile) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+		bytes -= n;
+	}
+
+	return true;
+}
+
+FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	FLAC__ASSERT(bytes >= 0);
+	while(bytes > 0) {
+		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;
+		}
+		if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+		bytes -= n;
+	}
+
+	return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	while(!feof(file)) {
+		n = fread(buffer, 1, sizeof(buffer), file);
+		if(n == 0 && !feof(file)) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	while(!eof_cb(handle)) {
+		n = read_cb(buffer, 1, sizeof(buffer), handle);
+		if(n == 0 && !eof_cb(handle)) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static int
+local_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+	va_list va;
+	int rc;
+
+#if defined _MSC_VER
+	if (size == 0)
+		return 1024;
+#endif
+
+	va_start (va, fmt);
+
+#if defined _MSC_VER
+	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) {
+		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;
+		}
+		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++;
+
+		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;
+		}
+		local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix);
+	}
+
+	if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != tempfile);
+	FLAC__ASSERT(0 != *tempfile);
+	FLAC__ASSERT(0 != tempfilename);
+	FLAC__ASSERT(0 != *tempfilename);
+	FLAC__ASSERT(0 != status);
+
+	(void)fclose(*tempfile);
+	*tempfile = 0;
+
+#if defined _MSC_VER || defined __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;
+	}
+#endif
+
+	/*@@@ 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;
+	}
+
+	cleanup_tempfile_(tempfile, tempfilename);
+
+	return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+	if(0 != *tempfile) {
+		(void)fclose(*tempfile);
+		*tempfile = 0;
+	}
+
+	if(0 != *tempfilename) {
+		(void)flac_unlink(*tempfilename);
+		free(*tempfilename);
+		*tempfilename = 0;
+	}
+}
+
+FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+	return (0 == flac_stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+	struct timespec srctime[2] = {};
+	srctime[0].tv_sec = stats->st_atime;
+	srctime[1].tv_sec = stats->st_mtime;
+#else
+	struct utimbuf srctime;
+	srctime.actime = stats->st_atime;
+	srctime.modtime = stats->st_mtime;
+#endif
+
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+
+	(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
+}
+
+int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+	return fseeko((FILE*)handle, (FLAC__off_t)offset, whence);
+}
+
+FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
+{
+	return ftello((FILE*)handle);
+}
+
+FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
+{
+	switch(status) {
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
+			return FLAC__METADATA_CHAIN_STATUS_OK;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
+			return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
+			return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
+			return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
+			return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
+			return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
+		default:
+			return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+	}
+}
diff --git a/src/libFLAC/metadata_object.c b/src/libFLAC/metadata_object.c
new file mode 100644
index 0000000..de8e513
--- /dev/null
+++ b/src/libFLAC/metadata_object.c
@@ -0,0 +1,1821 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/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
+ *
+ ***************************************************************************/
+
+/* 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, uint32_t bytes)
+{
+	FLAC__ASSERT(to != NULL);
+	if (bytes > 0 && from != NULL) {
+		FLAC__byte *x;
+		if ((x = safe_malloc_(bytes)) == NULL)
+			return false;
+		memcpy(x, from, bytes);
+		*to = x;
+	}
+	else {
+		*to = 0;
+	}
+	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, uint32_t bytes)
+{
+	FLAC__byte *copy;
+	FLAC__ASSERT(to != NULL);
+	if (copy_bytes_(&copy, from, bytes)) {
+		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, uint32_t length)
+{
+	FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1);
+	if (x != NULL) {
+		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 != NULL);
+	if (copy) {
+		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;
+	if (from->entry == 0) {
+		FLAC__ASSERT(from->length == 0);
+		to->entry = 0;
+	}
+	else {
+		FLAC__byte *x;
+		FLAC__ASSERT(from->length > 0);
+		if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL)
+			return false;
+		memcpy(x, from->entry, from->length);
+		x[from->length] = '\0';
+		to->entry = x;
+	}
+	return true;
+}
+
+static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
+{
+	memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+	if (from->indices == 0) {
+		FLAC__ASSERT(from->num_indices == 0);
+	}
+	else {
+		FLAC__StreamMetadata_CueSheet_Index *x;
+		FLAC__ASSERT(from->num_indices > 0);
+		if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL)
+			return false;
+		memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+		to->indices = x;
+	}
+	return true;
+}
+
+static void seektable_calculate_length_(FLAC__StreamMetadata *object)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+}
+
+static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points)
+{
+	FLAC__StreamMetadata_SeekPoint *object_array;
+
+	FLAC__ASSERT(num_points > 0);
+
+	object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
+
+	if (object_array != NULL) {
+		uint32_t i;
+		for (i = 0; i < num_points; i++) {
+			object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+			object_array[i].stream_offset = 0;
+			object_array[i].frame_samples = 0;
+		}
+	}
+
+	return object_array;
+}
+
+static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
+{
+	uint32_t i;
+
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
+	object->length += object->data.vorbis_comment.vendor_string.length;
+	object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
+	for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+		object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
+		object->length += object->data.vorbis_comment.comments[i].length;
+	}
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments)
+{
+	FLAC__ASSERT(num_comments > 0);
+
+	return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+}
+
+static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments)
+{
+	uint32_t i;
+
+	FLAC__ASSERT(object_array != NULL && num_comments > 0);
+
+	for (i = 0; i < num_comments; i++)
+		free(object_array[i].entry);
+
+	free(object_array);
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments)
+{
+	FLAC__StreamMetadata_VorbisComment_Entry *return_array;
+
+	FLAC__ASSERT(object_array != NULL);
+	FLAC__ASSERT(num_comments > 0);
+
+	return_array = vorbiscomment_entry_array_new_(num_comments);
+
+	if (return_array != NULL) {
+		uint32_t i;
+
+		for (i = 0; i < num_comments; i++) {
+			if (!copy_vcentry_(return_array+i, object_array+i)) {
+				vorbiscomment_entry_array_delete_(return_array, num_comments);
+				return 0;
+			}
+		}
+	}
+
+	return return_array;
+}
+
+static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
+{
+	FLAC__byte *save;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(dest != NULL);
+	FLAC__ASSERT(src != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT((src->entry != NULL && src->length > 0) || (src->entry == NULL && src->length == 0));
+
+	save = dest->entry;
+
+	if (src->entry != NULL) {
+		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 {
+		/* the src is null */
+		*dest = *src;
+	}
+
+	free(save);
+
+	vorbiscomment_calculate_length_(object);
+	return true;
+}
+
+static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length)
+{
+	uint32_t i;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(field_name != NULL);
+
+	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)
+{
+	uint32_t i;
+
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	object->length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+
+	object->length += object->data.cue_sheet.num_tracks * (
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+	) / 8;
+
+	for (i = 0; i < object->data.cue_sheet.num_tracks; i++) {
+		object->length += object->data.cue_sheet.tracks[i].num_indices * (
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+		) / 8;
+	}
+}
+
+static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices)
+{
+	FLAC__ASSERT(num_indices > 0);
+
+	return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks)
+{
+	FLAC__ASSERT(num_tracks > 0);
+
+	return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks)
+{
+	uint32_t i;
+
+	FLAC__ASSERT(object_array != NULL && num_tracks > 0);
+
+	for (i = 0; i < num_tracks; i++) {
+		if (object_array[i].indices != 0) {
+			FLAC__ASSERT(object_array[i].num_indices > 0);
+			free(object_array[i].indices);
+		}
+	}
+
+	free(object_array);
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks)
+{
+	FLAC__StreamMetadata_CueSheet_Track *return_array;
+
+	FLAC__ASSERT(object_array != NULL);
+	FLAC__ASSERT(num_tracks > 0);
+
+	return_array = cuesheet_track_array_new_(num_tracks);
+
+	if (return_array != NULL) {
+		uint32_t i;
+
+		for (i = 0; i < num_tracks; i++) {
+			if (!copy_track_(return_array+i, object_array+i)) {
+				cuesheet_track_array_delete_(return_array, num_tracks);
+				return 0;
+			}
+		}
+	}
+
+	return return_array;
+}
+
+static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_CueSheet_Index *save;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(dest != NULL);
+	FLAC__ASSERT(src != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT((src->indices != NULL && src->num_indices > 0) || (src->indices == NULL && src->num_indices == 0));
+
+	save = dest->indices;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if (copy) {
+		if (!copy_track_(dest, src))
+			return false;
+	}
+	else {
+		*dest = *src;
+	}
+
+	free(save);
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+
+/****************************************************************************
+ *
+ * Metadata object routines
+ *
+ ***************************************************************************/
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
+{
+	FLAC__StreamMetadata *object;
+
+	if (type > FLAC__MAX_METADATA_TYPE)
+		return 0;
+
+	object = calloc(1, sizeof(FLAC__StreamMetadata));
+	if (object != NULL) {
+		object->is_last = false;
+		object->type = type;
+		switch(type) {
+			case FLAC__METADATA_TYPE_STREAMINFO:
+				object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+				break;
+			case FLAC__METADATA_TYPE_PADDING:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_APPLICATION:
+				object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+				/* calloc() took care of this for us:
+				object->data.application.data = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_SEEKTABLE:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				object->data.seek_table.num_points = 0;
+				object->data.seek_table.points = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+				object->data.vorbis_comment.vendor_string.length = (uint32_t)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), "")) {
+					free(object->data.picture.mime_type);
+					free(object);
+					return 0;
+				}
+				break;
+			default:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				object->data.unknown.data = 0;
+				*/
+				break;
+		}
+	}
+
+	return object;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
+{
+	FLAC__StreamMetadata *to;
+
+	FLAC__ASSERT(object != NULL);
+
+	if ((to = FLAC__metadata_object_new(object->type)) != NULL) {
+		to->is_last = object->is_last;
+		to->type = object->type;
+		to->length = object->length;
+		switch(to->type) {
+			case FLAC__METADATA_TYPE_STREAMINFO:
+				memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
+				break;
+			case FLAC__METADATA_TYPE_PADDING:
+				break;
+			case FLAC__METADATA_TYPE_APPLICATION:
+				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);
+					return 0;
+				}
+				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;
+				}
+				break;
+			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+				if (to->data.vorbis_comment.vendor_string.entry != NULL) {
+					free(to->data.vorbis_comment.vendor_string.entry);
+					to->data.vorbis_comment.vendor_string.entry = 0;
+				}
+				if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				if (object->data.vorbis_comment.num_comments == 0) {
+					to->data.vorbis_comment.comments = 0;
+				}
+				else {
+					to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+					if (to->data.vorbis_comment.comments == NULL) {
+						to->data.vorbis_comment.num_comments = 0;
+						FLAC__metadata_object_delete(to);
+						return 0;
+					}
+				}
+				to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
+				break;
+			case FLAC__METADATA_TYPE_CUESHEET:
+				memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
+				if (object->data.cue_sheet.num_tracks == 0) {
+					FLAC__ASSERT(object->data.cue_sheet.tracks == NULL);
+				}
+				else {
+					FLAC__ASSERT(object->data.cue_sheet.tracks != 0);
+					to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+					if (to->data.cue_sheet.tracks == NULL) {
+						FLAC__metadata_object_delete(to);
+						return 0;
+					}
+				}
+				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);
+					return 0;
+				}
+				break;
+		}
+	}
+
+	return to;
+}
+
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
+{
+	FLAC__ASSERT(object != NULL);
+
+	switch(object->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+		case FLAC__METADATA_TYPE_PADDING:
+			break;
+		case FLAC__METADATA_TYPE_APPLICATION:
+			if (object->data.application.data != NULL) {
+				free(object->data.application.data);
+				object->data.application.data = NULL;
+			}
+			break;
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			if (object->data.seek_table.points != NULL) {
+				free(object->data.seek_table.points);
+				object->data.seek_table.points = NULL;
+			}
+			break;
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			if (object->data.vorbis_comment.vendor_string.entry != NULL) {
+				free(object->data.vorbis_comment.vendor_string.entry);
+				object->data.vorbis_comment.vendor_string.entry = 0;
+			}
+			if (object->data.vorbis_comment.comments != NULL) {
+				FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
+				vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+				object->data.vorbis_comment.comments = NULL;
+				object->data.vorbis_comment.num_comments = 0;
+			}
+			break;
+		case FLAC__METADATA_TYPE_CUESHEET:
+			if (object->data.cue_sheet.tracks != NULL) {
+				FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+				cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+				object->data.cue_sheet.tracks = NULL;
+				object->data.cue_sheet.num_tracks = 0;
+			}
+			break;
+		case FLAC__METADATA_TYPE_PICTURE:
+			if (object->data.picture.mime_type != NULL) {
+				free(object->data.picture.mime_type);
+				object->data.picture.mime_type = NULL;
+			}
+			if (object->data.picture.description != NULL) {
+				free(object->data.picture.description);
+				object->data.picture.description = NULL;
+			}
+			if (object->data.picture.data != NULL) {
+				free(object->data.picture.data);
+				object->data.picture.data = NULL;
+			}
+			break;
+		default:
+			if (object->data.unknown.data != NULL) {
+				free(object->data.unknown.data);
+				object->data.unknown.data = NULL;
+			}
+			break;
+	}
+}
+
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
+{
+	FLAC__metadata_object_delete_data(object);
+	free(object);
+}
+
+static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2)
+{
+	if (block1->min_blocksize != block2->min_blocksize)
+		return false;
+	if (block1->max_blocksize != block2->max_blocksize)
+		return false;
+	if (block1->min_framesize != block2->min_framesize)
+		return false;
+	if (block1->max_framesize != block2->max_framesize)
+		return false;
+	if (block1->sample_rate != block2->sample_rate)
+		return false;
+	if (block1->channels != block2->channels)
+		return false;
+	if (block1->bits_per_sample != block2->bits_per_sample)
+		return false;
+	if (block1->total_samples != block2->total_samples)
+		return false;
+	if (memcmp(block1->md5sum, block2->md5sum, 16) != 0)
+		return false;
+	return true;
+}
+
+static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, uint32_t block_length)
+{
+	FLAC__ASSERT(block1 != NULL);
+	FLAC__ASSERT(block2 != NULL);
+	FLAC__ASSERT(block_length >= sizeof(block1->id));
+
+	if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0)
+		return false;
+	if (block1->data != NULL && block2->data != NULL)
+		return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0;
+	else
+		return block1->data == block2->data;
+}
+
+static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
+{
+	uint32_t i;
+
+	FLAC__ASSERT(block1 != NULL);
+	FLAC__ASSERT(block2 != NULL);
+
+	if (block1->num_points != block2->num_points)
+		return false;
+
+	if (block1->points != NULL && block2->points != NULL) {
+		for (i = 0; i < block1->num_points; i++) {
+			if (block1->points[i].sample_number != block2->points[i].sample_number)
+				return false;
+			if (block1->points[i].stream_offset != block2->points[i].stream_offset)
+				return false;
+			if (block1->points[i].frame_samples != block2->points[i].frame_samples)
+				return false;
+		}
+		return true;
+	}
+	else
+		return block1->points == block2->points;
+}
+
+static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2)
+{
+	uint32_t i;
+
+	if (block1->vendor_string.length != block2->vendor_string.length)
+		return false;
+
+	if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) {
+		if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0)
+			return false;
+	}
+	else if (block1->vendor_string.entry != block2->vendor_string.entry)
+		return false;
+
+	if (block1->num_comments != block2->num_comments)
+		return false;
+
+	for (i = 0; i < block1->num_comments; i++) {
+		if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) {
+			if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0)
+				return false;
+		}
+		else if (block1->comments[i].entry != block2->comments[i].entry)
+			return false;
+	}
+	return true;
+}
+
+static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
+{
+	uint32_t i, j;
+
+	if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0)
+		return false;
+
+	if (block1->lead_in != block2->lead_in)
+		return false;
+
+	if (block1->is_cd != block2->is_cd)
+		return false;
+
+	if (block1->num_tracks != block2->num_tracks)
+		return false;
+
+	if (block1->tracks != NULL && block2->tracks != NULL) {
+		FLAC__ASSERT(block1->num_tracks > 0);
+		for (i = 0; i < block1->num_tracks; i++) {
+			if (block1->tracks[i].offset != block2->tracks[i].offset)
+				return false;
+			if (block1->tracks[i].number != block2->tracks[i].number)
+				return false;
+			if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0)
+				return false;
+			if (block1->tracks[i].type != block2->tracks[i].type)
+				return false;
+			if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
+				return false;
+			if (block1->tracks[i].num_indices != block2->tracks[i].num_indices)
+				return false;
+			if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) {
+				FLAC__ASSERT(block1->tracks[i].num_indices > 0);
+				for (j = 0; j < block1->tracks[i].num_indices; j++) {
+					if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
+						return false;
+					if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
+						return false;
+				}
+			}
+			else if (block1->tracks[i].indices != block2->tracks[i].indices)
+				return false;
+		}
+	}
+	else if (block1->tracks != block2->tracks)
+		return false;
+	return true;
+}
+
+static FLAC__bool compare_block_data_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 && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type)))
+		return false;
+	if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || 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 && (block1->data == NULL || block2->data == NULL || 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, uint32_t block_length)
+{
+	FLAC__ASSERT(block1 != NULL);
+	FLAC__ASSERT(block2 != NULL);
+
+	if (block1->data != NULL && block2->data != NULL)
+		return memcmp(block1->data, block2->data, block_length) == 0;
+	else
+		return block1->data == block2->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
+{
+	FLAC__ASSERT(block1 != NULL);
+	FLAC__ASSERT(block2 != NULL);
+
+	if (block1->type != block2->type) {
+		return false;
+	}
+	if (block1->is_last != block2->is_last) {
+		return false;
+	}
+	if (block1->length != block2->length) {
+		return false;
+	}
+	switch(block1->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return true; /* we don't compare the padding guts */
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
+		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);
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy)
+{
+	FLAC__byte *save;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
+	FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false));
+
+	save = object->data.application.data;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if (copy) {
+		if (!copy_bytes_(&object->data.application.data, data, length))
+			return false;
+	}
+	else {
+		object->data.application.data = data;
+	}
+
+	free(save);
+
+	object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	if (object->data.seek_table.points == 0) {
+		FLAC__ASSERT(object->data.seek_table.num_points == 0);
+		if (new_num_points == 0)
+			return true;
+		else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0)
+			return false;
+	}
+	else {
+		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) {
+			free(object->data.seek_table.points);
+			object->data.seek_table.points = 0;
+		}
+		else if ((object->data.seek_table.points = safe_realloc_(object->data.seek_table.points, new_size)) == NULL)
+			return false;
+
+		/* if growing, set new elements to placeholders */
+		if (new_size > old_size) {
+			uint32_t i;
+			for (i = object->data.seek_table.num_points; i < new_num_points; i++) {
+				object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+				object->data.seek_table.points[i].stream_offset = 0;
+				object->data.seek_table.points[i].frame_samples = 0;
+			}
+		}
+	}
+
+	object->data.seek_table.num_points = new_num_points;
+
+	seektable_calculate_length_(object);
+	return true;
+}
+
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
+
+	object->data.seek_table.points[point_num] = point;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+	int i;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(point_num <= object->data.seek_table.num_points);
+
+	if (!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
+		return false;
+
+	/* move all points >= point_num forward one space */
+	for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
+		object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
+
+	FLAC__metadata_object_seektable_set_point(object, point_num, point);
+	seektable_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num)
+{
+	uint32_t i;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
+
+	/* move all points > point_num backward one space */
+	for (i = point_num; i < object->data.seek_table.num_points-1; i++)
+		object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
+
+	return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	return FLAC__format_seektable_is_legal(&object->data.seek_table);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	if (num > 0)
+		/* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
+		return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
+	else
+		return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
+{
+	FLAC__StreamMetadata_SeekTable *seek_table;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	seek_table = &object->data.seek_table;
+
+	if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
+		return false;
+
+	seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
+	seek_table->points[seek_table->num_points - 1].stream_offset = 0;
+	seek_table->points[seek_table->num_points - 1].frame_samples = 0;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(sample_numbers != 0 || num == 0);
+
+	if (num > 0) {
+		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+		uint32_t i, j;
+
+		i = seek_table->num_points;
+
+		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+			return false;
+
+		for (j = 0; j < num; i++, j++) {
+			seek_table->points[i].sample_number = sample_numbers[j];
+			seek_table->points[i].stream_offset = 0;
+			seek_table->points[i].frame_samples = 0;
+		}
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(total_samples > 0);
+
+	if (num > 0 && total_samples > 0) {
+		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+		uint32_t i, j;
+
+		i = seek_table->num_points;
+
+		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+			return false;
+
+		for (j = 0; j < num; i++, j++) {
+			seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
+			seek_table->points[i].stream_offset = 0;
+			seek_table->points[i].frame_samples = 0;
+		}
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples)
+{
+	FLAC__ASSERT(object != NULL);
+	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;
+		uint32_t 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--;
+
+		/* Put a strict upper bound on the number of allowed seek points. */
+		if (num > 32768) {
+			/* Set the bound and recalculate samples accordingly. */
+			num = 32768;
+			samples = total_samples / num;
+		}
+
+		i = seek_table->num_points;
+
+		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (uint32_t)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)
+{
+	uint32_t unique;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	unique = FLAC__format_seektable_sort(&object->data.seek_table);
+
+	return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	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);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if (object->data.vorbis_comment.comments == NULL) {
+		FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0);
+		if (new_num_comments == 0)
+			return true;
+		else if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL)
+			return false;
+	}
+	else {
+		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 */
+		if (new_num_comments < object->data.vorbis_comment.num_comments) {
+			uint32_t i;
+			for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
+				if (object->data.vorbis_comment.comments[i].entry != NULL)
+					free(object->data.vorbis_comment.comments[i].entry);
+		}
+
+		if (new_size == 0) {
+			free(object->data.vorbis_comment.comments);
+			object->data.vorbis_comment.comments = 0;
+		}
+		else {
+			FLAC__StreamMetadata_VorbisComment_Entry *oldptr = object->data.vorbis_comment.comments;
+			if ((object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) {
+				vorbiscomment_entry_array_delete_(oldptr, object->data.vorbis_comment.num_comments);
+				object->data.vorbis_comment.num_comments = 0;
+				return false;
+			}
+		}
+
+		/* if growing, zero all the length/pointers of new elements */
+		if (new_size > old_size)
+			memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
+	}
+
+	object->data.vorbis_comment.num_comments = new_num_comments;
+
+	vorbiscomment_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	FLAC__ASSERT(object != NULL);
+	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);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_VorbisComment *vc;
+
+	FLAC__ASSERT(object != NULL);
+	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))
+		return false;
+
+	/* move all comments >= comment_num forward one space */
+	memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
+	vc->comments[comment_num].length = 0;
+	vc->comments[comment_num].entry = 0;
+
+	return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	FLAC__ASSERT(object != NULL);
+	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(entry.entry != NULL && 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);
+
+		if (eq == NULL)
+			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) {
+			uint32_t indx = (uint32_t)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 = (uint32_t)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, uint32_t comment_num)
+{
+	FLAC__StreamMetadata_VorbisComment *vc;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
+
+	vc = &object->data.vorbis_comment;
+
+	/* free the comment at comment_num */
+	free(vc->comments[comment_num].entry);
+
+	/* move all comments > comment_num backward one space */
+	memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
+	vc->comments[vc->num_comments-1].length = 0;
+	vc->comments[vc->num_comments-1].entry = 0;
+
+	return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
+{
+	FLAC__ASSERT(entry != NULL);
+	FLAC__ASSERT(field_name != NULL);
+	FLAC__ASSERT(field_value != NULL);
+
+	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, (uint32_t)(-1)))
+		return false;
+
+	{
+		const size_t nn = strlen(field_name);
+		const size_t nv = strlen(field_value);
+		entry->length = nn + 1 /*=*/ + nv;
+		if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL)
+			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 FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
+{
+	FLAC__ASSERT(entry.entry != NULL && entry.length > 0);
+	FLAC__ASSERT(field_name != NULL);
+	FLAC__ASSERT(field_value != NULL);
+
+	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
+
+	{
+		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 '=' */
+
+		if (eq == NULL)
+			return false; /* double protection */
+		if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL)
+			return false;
+		if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) {
+			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 true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length)
+{
+	FLAC__ASSERT(entry.entry != NULL && entry.length > 0);
+	{
+		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+		return (eq != NULL && (uint32_t)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0);
+	}
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name)
+{
+	FLAC__ASSERT(field_name != NULL);
+
+	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 uint32_t field_name_length = strlen(field_name);
+	uint32_t i;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+			if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
+				return -1;
+			else
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+	FLAC__bool ok = true;
+	uint32_t matching = 0;
+	const uint32_t field_name_length = strlen(field_name);
+	int i;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	/* must delete from end to start otherwise it will interfere with our iteration */
+	for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
+		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+			matching++;
+			ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (uint32_t)i);
+		}
+	}
+
+	return ok? (int)matching : -1;
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
+{
+	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)
+{
+	FLAC__StreamMetadata_CueSheet_Track *to;
+
+	FLAC__ASSERT(object != NULL);
+
+	if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) {
+		if (!copy_track_(to, object)) {
+			FLAC__metadata_object_cuesheet_track_delete(to);
+			return 0;
+		}
+	}
+
+	return to;
+}
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+	FLAC__ASSERT(object != NULL);
+
+	if (object->indices != NULL) {
+		FLAC__ASSERT(object->num_indices > 0);
+		free(object->indices);
+	}
+}
+
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+	FLAC__metadata_object_cuesheet_track_delete_data(object);
+	free(object);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	if (track->indices == NULL) {
+		FLAC__ASSERT(track->num_indices == 0);
+		if (new_num_indices == 0)
+			return true;
+		else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL)
+			return false;
+	}
+	else {
+		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) {
+			free(track->indices);
+			track->indices = 0;
+		}
+		else if ((track->indices = safe_realloc_(track->indices, new_size)) == NULL)
+			return false;
+
+		/* if growing, zero all the lengths/pointers of new elements */
+		if (new_size > old_size)
+			memset(track->indices + track->num_indices, 0, new_size - old_size);
+	}
+
+	track->num_indices = new_num_indices;
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+	FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
+		return false;
+
+	/* move all indices >= index_num forward one space */
+	memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
+
+	track->indices[index_num] = indx;
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num)
+{
+	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, uint32_t track_num, uint32_t index_num)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+	FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	/* move all indices > index_num backward one space */
+	memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
+
+	FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	if (object->data.cue_sheet.tracks == NULL) {
+		FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
+		if (new_num_tracks == 0)
+			return true;
+		else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL)
+			return false;
+	}
+	else {
+		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 */
+		if (new_num_tracks < object->data.cue_sheet.num_tracks) {
+			uint32_t i;
+			for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
+				free(object->data.cue_sheet.tracks[i].indices);
+		}
+
+		if (new_size == 0) {
+			free(object->data.cue_sheet.tracks);
+			object->data.cue_sheet.tracks = 0;
+		}
+		else if ((object->data.cue_sheet.tracks = safe_realloc_(object->data.cue_sheet.tracks, new_size)) == NULL)
+			return false;
+
+		/* if growing, zero all the lengths/pointers of new elements */
+		if (new_size > old_size)
+			memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
+	}
+
+	object->data.cue_sheet.num_tracks = new_num_tracks;
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+	return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_CueSheet *cs;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks);
+
+	cs = &object->data.cue_sheet;
+
+	if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
+		return false;
+
+	/* move all tracks >= track_num forward one space */
+	memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
+	cs->tracks[track_num].num_indices = 0;
+	cs->tracks[track_num].indices = 0;
+
+	return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num)
+{
+	FLAC__StreamMetadata_CueSheet_Track track;
+	memset(&track, 0, sizeof(track));
+	return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num)
+{
+	FLAC__StreamMetadata_CueSheet *cs;
+
+	FLAC__ASSERT(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+	cs = &object->data.cue_sheet;
+
+	/* free the track at track_num */
+	free(cs->tracks[track_num].indices);
+
+	/* move all tracks > track_num backward one space */
+	memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
+	cs->tracks[cs->num_tracks-1].num_indices = 0;
+	cs->tracks[cs->num_tracks-1].indices = 0;
+
+	return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
+{
+	FLAC__ASSERT(object != NULL);
+	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, uint32_t 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(object != NULL);
+	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(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT(mime_type != NULL);
+
+	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;
+	}
+
+	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(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT(description != NULL);
+
+	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;
+	}
+
+	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(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && 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;
+	}
+
+	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(object != NULL);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+
+	return FLAC__format_picture_is_legal(&object->data.picture, violation);
+}
diff --git a/src/libFLAC/ogg_decoder_aspect.c b/src/libFLAC/ogg_decoder_aspect.c
new file mode 100644
index 0000000..7c814a2
--- /dev/null
+++ b/src/libFLAC/ogg_decoder_aspect.c
@@ -0,0 +1,251 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 accommodate 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 uint32_t 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 = (uint32_t)(*b);
+						b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
+						aspect->version_minor = (uint32_t)(*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;
+}
diff --git a/src/libFLAC/ogg_encoder_aspect.c b/src/libFLAC/ogg_encoder_aspect.c
new file mode 100644
index 0000000..a655da9
--- /dev/null
+++ b/src/libFLAC/ogg_encoder_aspect.c
@@ -0,0 +1,228 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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, uint32_t 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, uint32_t samples, uint32_t 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 = (uint8_t *)synthetic_first_packet_body;
+			packet.bytes = sizeof(synthetic_first_packet_body);
+
+			packet.b_o_s = 1;
+			aspect->is_first_packet = false;
+		}
+		else {
+			packet.packet = (uint8_t *)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;
+}
diff --git a/src/libFLAC/ogg_helper.c b/src/libFLAC/ogg_helper.c
new file mode 100644
index 0000000..cbe5bc6
--- /dev/null
+++ b/src/libFLAC/ogg_helper.c
@@ -0,0 +1,210 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 uint32_t OGG_HEADER_FIXED_PORTION_LEN = 27;
+	static const uint32_t 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;
+
+	{
+		uint32_t i;
+
+		/* check to see that it specifies a single packet */
+		for(i = 0; i < (uint32_t)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;
+}
diff --git a/src/libFLAC/ogg_mapping.c b/src/libFLAC/ogg_mapping.c
new file mode 100644
index 0000000..f6de600
--- /dev/null
+++ b/src/libFLAC/ogg_mapping.c
@@ -0,0 +1,48 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 uint32_t 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 uint32_t FLAC__OGG_MAPPING_VERSION_MAJOR_LEN = 8; /* bits */
+const uint32_t FLAC__OGG_MAPPING_VERSION_MINOR_LEN = 8; /* bits */
+
+const uint32_t FLAC__OGG_MAPPING_NUM_HEADERS_LEN = 16; /* bits */
diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c
new file mode 100644
index 0000000..6707017
--- /dev/null
+++ b/src/libFLAC/stream_decoder.c
@@ -0,0 +1,3409 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 <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/bitreader.h"
+#include "private/bitmath.h"
+#include "private/cpu.h"
+#include "private/crc.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+#include "private/macros.h"
+
+
+/* technically this should be in an "export.c" but this is convenient enough */
+FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC = FLAC__HAS_OGG;
+
+
+/***********************************************************************
+ *
+ * Private static data
+ *
+ ***********************************************************************/
+
+static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamDecoder *decoder);
+static FILE *get_binary_stdin_(void);
+static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels);
+static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id);
+static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length);
+static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length);
+static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t 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);
+static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t 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[], 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);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamDecoderPrivate {
+	FLAC__bool is_ogg;
+	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;
+	/* generic 32-bit datapath: */
+	void (*local_lpc_restore_signal)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+	/* generic 64-bit datapath: */
+	void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t 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[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+	void *client_data;
+	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];
+	uint32_t output_capacity, output_channels;
+	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;
+	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;
+	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;
+	FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */
+	FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */
+	/* unaligned (original) pointers to allocated data */
+	FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS];
+	FLAC__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;
+	uint32_t unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */
+	FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */
+} FLAC__StreamDecoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
+	"FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
+	"FLAC__STREAM_DECODER_READ_METADATA",
+	"FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
+	"FLAC__STREAM_DECODER_READ_FRAME",
+	"FLAC__STREAM_DECODER_END_OF_STREAM",
+	"FLAC__STREAM_DECODER_OGG_ERROR",
+	"FLAC__STREAM_DECODER_SEEK_ERROR",
+	"FLAC__STREAM_DECODER_ABORTED",
+	"FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
+	"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",
+	"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"
+};
+
+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_UNPARSEABLE_STREAM"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
+{
+	FLAC__StreamDecoder *decoder;
+	uint32_t i;
+
+	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+	decoder = calloc(1, sizeof(FLAC__StreamDecoder));
+	if(decoder == 0) {
+		return 0;
+	}
+
+	decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected));
+	if(decoder->protected_ == 0) {
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_ = calloc(1, sizeof(FLAC__StreamDecoderPrivate));
+	if(decoder->private_ == 0) {
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->input = FLAC__bitreader_new();
+	if(decoder->private_->input == 0) {
+		free(decoder->private_);
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->metadata_filter_ids_capacity = 16;
+	if(0 == (decoder->private_->metadata_filter_ids = 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);
+		return 0;
+	}
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		decoder->private_->output[i] = 0;
+		decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+	}
+
+	decoder->private_->output_capacity = 0;
+	decoder->private_->output_channels = 0;
+	decoder->private_->has_seek_table = false;
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
+
+	decoder->private_->file = 0;
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+	return decoder;
+}
+
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
+{
+	uint32_t i;
+
+	if (decoder == NULL)
+		return ;
+
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->private_->input);
+
+	(void)FLAC__stream_decoder_finish(decoder);
+
+	if(0 != decoder->private_->metadata_filter_ids)
+		free(decoder->private_->metadata_filter_ids);
+
+	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]);
+
+	free(decoder->private_);
+	free(decoder->protected_);
+	free(decoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+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 FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	if(FLAC__HAS_OGG == 0 && is_ogg)
+		return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+
+	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;
+
+#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
+	 */
+	FLAC__cpu_info(&decoder->private_->cpuinfo);
+	/* first default to the non-asm routines */
+	decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
+	decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
+	decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
+	/* now override with asm where appropriate */
+#ifndef FLAC__NO_ASM
+	if(decoder->private_->cpuinfo.use_asm) {
+#ifdef FLAC__CPU_IA32
+		FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+#ifdef FLAC__HAS_NASM
+		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.x86.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;
+		}
+		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;
+		}
+#endif
+#if FLAC__HAS_X86INTRIN && ! defined FLAC__INTEGER_ONLY_LIBRARY
+# if defined FLAC__SSE4_1_SUPPORTED
+		if (decoder->private_->cpuinfo.x86.sse41) {
+#  if !defined FLAC__HAS_NASM  /* these are not undoubtedly faster than their MMX ASM counterparts */
+			decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_intrin_sse41;
+			decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_16_intrin_sse41;
+#  endif
+			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
+
+	/* from here on, errors are fatal */
+
+	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 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;
+	uint32_t i;
+
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+		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);
+
+	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__bitreader_free(decoder->private_->input);
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		/* WATCHOUT:
+		 * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN()
+		 * require that the output arrays have a buffer of up to 3 zeroes
+		 * in front (at negative indices) for alignment purposes;
+		 * we use 4 to keep the data well-aligned.
+		 */
+		if(0 != decoder->private_->output[i]) {
+			free(decoder->private_->output[i]-4);
+			decoder->private_->output[i] = 0;
+		}
+		if(0 != decoder->private_->residual_unaligned[i]) {
+			free(decoder->private_->residual_unaligned[i]);
+			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+		}
+	}
+	decoder->private_->output_capacity = 0;
+	decoder->private_->output_channels = 0;
+
+#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;
+
+	return !md5_failed;
+}
+
+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_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+#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_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->protected_->md5_checking = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE);
+	/* double protection */
+	if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE)
+		return false;
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_filter[type] = true;
+	if(type == FLAC__METADATA_TYPE_APPLICATION)
+		decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != id);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+		return true;
+
+	FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
+
+	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+		if(0 == (decoder->private_->metadata_filter_ids = 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;
+	}
+
+	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+	decoder->private_->metadata_filter_ids_count++;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
+{
+	uint32_t i;
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
+		decoder->private_->metadata_filter[i] = true;
+	decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE);
+	/* double protection */
+	if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE)
+		return false;
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_filter[type] = false;
+	if(type == FLAC__METADATA_TYPE_APPLICATION)
+		decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != id);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+		return true;
+
+	FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
+
+	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+		if(0 == (decoder->private_->metadata_filter_ids = 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;
+	}
+
+	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+	decoder->private_->metadata_filter_ids_count++;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+	decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->state;
+}
+
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
+{
+	return FLAC__StreamDecoderStateString[decoder->protected_->state];
+}
+
+FLAC_API 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 uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->channels;
+}
+
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->channel_assignment;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->bits_per_sample;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->sample_rate;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->blocksize;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_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 && decoder->private_->is_ogg)
+		return false;
+
+	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);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	if(!decoder->private_->internal_reset_hack && decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	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;
+	}
+	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	if(!FLAC__stream_decoder_flush(decoder)) {
+		/* 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_->has_stream_info = false;
+
+	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;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool got_a_frame;
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				else
+					return true;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
+					return false; /* above function sets the status for us */
+				if(got_a_frame)
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				FLAC__ASSERT(0);
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+			case FLAC__STREAM_DECODER_READ_FRAME:
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				FLAC__ASSERT(0);
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool dummy;
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				FLAC__ASSERT(0);
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool got_a_frame;
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				return false; /* above function sets the status for us */
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
+					return false; /* above function sets the status for us */
+				if(got_a_frame)
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				FLAC__ASSERT(0);
+				return false;
+		}
+	}
+}
+
+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
+ *
+ ***********************************************************************/
+
+uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	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;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamDecoder *decoder)
+{
+	decoder->private_->is_ogg = false;
+	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;
+
+	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 __EMX__
+	setmode(fileno(stdin), O_BINARY);
+#endif
+
+	return stdin;
+}
+
+FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels)
+{
+	uint32_t i;
+	FLAC__int32 *tmp;
+
+	if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
+		return true;
+
+	/* simply using realloc() is not practical because the number of channels may change mid-stream */
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		if(0 != decoder->private_->output[i]) {
+			free(decoder->private_->output[i]-4);
+			decoder->private_->output[i] = 0;
+		}
+		if(0 != decoder->private_->residual_unaligned[i]) {
+			free(decoder->private_->residual_unaligned[i]);
+			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+		}
+	}
+
+	for(i = 0; i < channels; i++) {
+		/* WATCHOUT:
+		 * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN()
+		 * require that the output arrays have a buffer of up to 3 zeroes
+		 * in front (at negative indices) for alignment purposes;
+		 * we use 4 to keep the data well-aligned.
+		 */
+		tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/);
+		if(tmp == 0) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		memset(tmp, 0, sizeof(FLAC__int32)*4);
+		decoder->private_->output[i] = tmp + 4;
+
+		if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+	}
+
+	decoder->private_->output_capacity = size;
+	decoder->private_->output_channels = channels;
+
+	return true;
+}
+
+FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
+{
+	size_t i;
+
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+
+	for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
+		if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
+			return true;
+
+	return false;
+}
+
+FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	uint32_t i, id;
+	FLAC__bool first = true;
+
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+	for(i = id = 0; i < 4; ) {
+		if(decoder->private_->cached) {
+			x = (FLAC__uint32)decoder->private_->lookahead;
+			decoder->private_->cached = false;
+		}
+		else {
+			if(!FLAC__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;
+			i++;
+			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; /* 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__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 */
+			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+				decoder->private_->lookahead = (FLAC__byte)x;
+				decoder->private_->cached = true;
+			}
+			else if(x >> 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;
+			}
+		}
+		i = 0;
+		if(first) {
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+			first = false;
+		}
+	}
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
+	return true;
+}
+
+FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool is_last;
+	FLAC__uint32 i, x, type, length;
+
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+	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__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN))
+		return false; /* 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))
+			return false;
+
+		decoder->private_->has_stream_info = true;
+		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) {
+		/* just in case we already have a seek table, and reading the next one fails: */
+		decoder->private_->has_seek_table = false;
+
+		if(!read_metadata_seektable_(decoder, is_last, length))
+			return false;
+
+		decoder->private_->has_seek_table = true;
+		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 {
+		FLAC__bool skip_it = !decoder->private_->metadata_filter[type];
+		uint32_t 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__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))
+				skip_it = !skip_it;
+		}
+
+		if(skip_it) {
+			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__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 = malloc(real_length))) {
+							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+							ok = false;
+						}
+						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, real_length))
+						ok = false;
+					break;
+				case FLAC__METADATA_TYPE_CUESHEET:
+					if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
+						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);
+					break;
+				default:
+					if(real_length > 0) {
+						if(0 == (block.data.unknown.data = malloc(real_length))) {
+							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+							ok = false;
+						}
+						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;
+			}
+			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 */
+			switch(type) {
+				case FLAC__METADATA_TYPE_PADDING:
+					break;
+				case FLAC__METADATA_TYPE_APPLICATION:
+					if(0 != block.data.application.data)
+						free(block.data.application.data);
+					break;
+				case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+					if(0 != block.data.vorbis_comment.vendor_string.entry)
+						free(block.data.vorbis_comment.vendor_string.entry);
+					if(block.data.vorbis_comment.num_comments > 0)
+						for(i = 0; i < block.data.vorbis_comment.num_comments; i++)
+							if(0 != block.data.vorbis_comment.comments[i].entry)
+								free(block.data.vorbis_comment.comments[i].entry);
+					if(0 != block.data.vorbis_comment.comments)
+						free(block.data.vorbis_comment.comments);
+					break;
+				case FLAC__METADATA_TYPE_CUESHEET:
+					if(block.data.cue_sheet.num_tracks > 0)
+						for(i = 0; i < block.data.cue_sheet.num_tracks; i++)
+							if(0 != block.data.cue_sheet.tracks[i].indices)
+								free(block.data.cue_sheet.tracks[i].indices);
+					if(0 != block.data.cue_sheet.tracks)
+						free(block.data.cue_sheet.tracks);
+					break;
+				case FLAC__METADATA_TYPE_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);
+				default:
+					if(0 != block.data.unknown.data)
+						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 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;
+}
+
+FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length)
+{
+	FLAC__uint32 x;
+	uint32_t bits, used_bits = 0;
+
+	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;
+	decoder->private_->stream_info.length = length;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN;
+	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__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__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__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__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__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__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__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__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);
+	if (length < (used_bits / 8))
+		return false; /* read_callback_ sets the state for us */
+	length -= (used_bits / 8);
+	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_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length)
+{
+	FLAC__uint32 i, x;
+	FLAC__uint64 xx;
+
+	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;
+	decoder->private_->seek_table.length = length;
+
+	decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+	/* use realloc since we may pass through here several times (e.g. after seeking) */
+	if(0 == (decoder->private_->seek_table.data.seek_table.points = 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__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__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__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 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, uint32_t length)
+{
+	FLAC__uint32 i;
+
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+	/* read vendor string */
+	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';
+		}
+		else
+			obj->vendor_string.entry = 0;
+
+		/* 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 > 100000) {
+			/* Possibly malicious file. */
+			obj->num_comments = 0;
+			return false;
+		}
+		if (obj->num_comments > 0) {
+			if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+				obj->num_comments = 0;
+				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+			for (i = 0; i < obj->num_comments; i++) {
+				/* Initialize here just to make sure. */
+				obj->comments[i].length = 0;
+				obj->comments[i].entry = 0;
+
+				FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+				if (length < 4) {
+					obj->num_comments = i;
+					goto skip;
+				}
+				else
+					length -= 4;
+				if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) {
+					obj->num_comments = i;
+					return false; /* read_callback_ sets the state for us */
+				}
+				if (obj->comments[i].length > 0) {
+					if (length < obj->comments[i].length) {
+						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;
+						obj->num_comments = i;
+						return false;
+					}
+					memset (obj->comments[i].entry, 0, obj->comments[i].length) ;
+					if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) {
+						/* Current i-th entry is bad, so we delete it. */
+						free (obj->comments[i].entry) ;
+						obj->comments[i].entry = NULL ;
+						obj->num_comments = i;
+						goto skip;
+					}
+					obj->comments[i].entry[obj->comments[i].length] = '\0';
+				}
+				else
+					obj->comments[i].entry = 0;
+			}
+		}
+	}
+
+  skip:
+	if (length > 0) {
+		/* length > 0 can only happen on files with invalid data in comments */
+		if(obj->num_comments < 1) {
+			free(obj->comments);
+			obj->comments = NULL;
+		}
+		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_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj)
+{
+	FLAC__uint32 i, j, x;
+
+	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__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__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__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__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__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 = 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__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__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__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__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__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__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__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 = 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 *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__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__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+						return false; /* read_callback_ sets the state for us */
+				}
+			}
+		}
+	}
+
+	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;
+	uint32_t i, skip;
+
+	/* skip the version and flags bytes */
+	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__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__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip))
+		return false; /* read_callback_ sets the state for us */
+	return true;
+}
+
+FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	FLAC__bool first = true;
+
+	/* If we know the total number of samples in the stream, stop if we've read that many. */
+	/* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */
+	if(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;
+		}
+	}
+
+	/* make sure we're byte aligned */
+	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) {
+		if(decoder->private_->cached) {
+			x = (FLAC__uint32)decoder->private_->lookahead;
+			decoder->private_->cached = false;
+		}
+		else {
+			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__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 */
+			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+				decoder->private_->lookahead = (FLAC__byte)x;
+				decoder->private_->cached = true;
+			}
+			else if(x >> 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;
+			}
+		}
+		if(first) {
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+			first = false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode)
+{
+	uint32_t channel;
+	uint32_t i;
+	FLAC__int32 mid, side;
+	uint32_t frame_crc; /* the one we calculate from the input stream */
+	FLAC__uint32 x;
+
+	*got_a_frame = false;
+
+	/* init the CRC */
+	frame_crc = 0;
+	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) /* 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;
+	for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+		/*
+		 * first figure the correct bits-per-sample of the subframe
+		 */
+		uint32_t bps = decoder->private_->frame.header.bits_per_sample;
+		switch(decoder->private_->frame.header.channel_assignment) {
+			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+				/* no adjustment needed */
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+				if(channel == 1)
+					bps++;
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+				if(channel == 0)
+					bps++;
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+				if(channel == 1)
+					bps++;
+				break;
+			default:
+				FLAC__ASSERT(0);
+		}
+		/*
+		 * now read it
+		 */
+		if(!read_subframe_(decoder, channel, bps, do_full_decode))
+			return false;
+		if(decoder->protected_->state == FLAC__STREAM_DECODER_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__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) {
+				case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+					/* do nothing */
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+						decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+						decoder->private_->output[0][i] += decoder->private_->output[1][i];
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+#if 1
+						mid = decoder->private_->output[0][i];
+						side = decoder->private_->output[1][i];
+						mid = ((uint32_t) mid) << 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:
+					FLAC__ASSERT(0);
+					break;
+			}
+		}
+	}
+	else {
+		/* Bad frame, emit error and zero the output signal */
+		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);
+			}
+		}
+	}
+
+	*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;
+	decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample;
+	decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate;
+	decoder->protected_->blocksize = decoder->private_->frame.header.blocksize;
+
+	FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+	decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
+
+	/* write it */
+	if(do_full_decode) {
+		if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+			return false;
+		}
+	}
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+	return true;
+}
+
+FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	FLAC__uint64 xx;
+	uint32_t i, blocksize_hint = 0, sample_rate_hint = 0;
+	FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */
+	uint32_t raw_header_len;
+	FLAC__bool is_unparseable = false;
+
+	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];
+	raw_header[1] = decoder->private_->header_warmup[1];
+	raw_header_len = 2;
+
+	/* 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.
+	 */
+
+	/*
+	 * 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__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;
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		}
+		raw_header[raw_header_len++] = (FLAC__byte)x;
+	}
+
+	switch(x = raw_header[2] >> 4) {
+		case 0:
+			is_unparseable = true;
+			break;
+		case 1:
+			decoder->private_->frame.header.blocksize = 192;
+			break;
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+			decoder->private_->frame.header.blocksize = 576 << (x-2);
+			break;
+		case 6:
+		case 7:
+			blocksize_hint = x;
+			break;
+		case 8:
+		case 9:
+		case 10:
+		case 11:
+		case 12:
+		case 13:
+		case 14:
+		case 15:
+			decoder->private_->frame.header.blocksize = 256 << (x-8);
+			break;
+		default:
+			FLAC__ASSERT(0);
+			break;
+	}
+
+	switch(x = raw_header[2] & 0x0f) {
+		case 0:
+			if(decoder->private_->has_stream_info)
+				decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate;
+			else
+				is_unparseable = true;
+			break;
+		case 1:
+			decoder->private_->frame.header.sample_rate = 88200;
+			break;
+		case 2:
+			decoder->private_->frame.header.sample_rate = 176400;
+			break;
+		case 3:
+			decoder->private_->frame.header.sample_rate = 192000;
+			break;
+		case 4:
+			decoder->private_->frame.header.sample_rate = 8000;
+			break;
+		case 5:
+			decoder->private_->frame.header.sample_rate = 16000;
+			break;
+		case 6:
+			decoder->private_->frame.header.sample_rate = 22050;
+			break;
+		case 7:
+			decoder->private_->frame.header.sample_rate = 24000;
+			break;
+		case 8:
+			decoder->private_->frame.header.sample_rate = 32000;
+			break;
+		case 9:
+			decoder->private_->frame.header.sample_rate = 44100;
+			break;
+		case 10:
+			decoder->private_->frame.header.sample_rate = 48000;
+			break;
+		case 11:
+			decoder->private_->frame.header.sample_rate = 96000;
+			break;
+		case 12:
+		case 13:
+		case 14:
+			sample_rate_hint = x;
+			break;
+		case 15:
+			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:
+			FLAC__ASSERT(0);
+	}
+
+	x = (uint32_t)(raw_header[3] >> 4);
+	if(x & 8) {
+		decoder->private_->frame.header.channels = 2;
+		switch(x & 7) {
+			case 0:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
+				break;
+			case 1:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
+				break;
+			case 2:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
+				break;
+			default:
+				is_unparseable = true;
+				break;
+		}
+	}
+	else {
+		decoder->private_->frame.header.channels = (uint32_t)x + 1;
+		decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+	}
+
+	switch(x = (uint32_t)(raw_header[3] & 0x0e) >> 1) {
+		case 0:
+			if(decoder->private_->has_stream_info)
+				decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+			else
+				is_unparseable = true;
+			break;
+		case 1:
+			decoder->private_->frame.header.bits_per_sample = 8;
+			break;
+		case 2:
+			decoder->private_->frame.header.bits_per_sample = 12;
+			break;
+		case 4:
+			decoder->private_->frame.header.bits_per_sample = 16;
+			break;
+		case 5:
+			decoder->private_->frame.header.bits_per_sample = 20;
+			break;
+		case 6:
+			decoder->private_->frame.header.bits_per_sample = 24;
+			break;
+		case 3:
+		case 7:
+			is_unparseable = true;
+			break;
+		default:
+			FLAC__ASSERT(0);
+			break;
+	}
+
+	/* check to make sure that reserved bit is 0 */
+	if(raw_header[3] & 0x01) /* MAGIC NUMBER */
+		is_unparseable = true;
+
+	/* 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;
+			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_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+		decoder->private_->frame.header.number.sample_number = xx;
+	}
+	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;
+			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_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+		decoder->private_->frame.header.number.frame_number = x;
+	}
+
+	if(blocksize_hint) {
+		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__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;
+		}
+		decoder->private_->frame.header.blocksize = x+1;
+	}
+
+	if(sample_rate_hint) {
+		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__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;
+		}
+		if(sample_rate_hint == 12)
+			decoder->private_->frame.header.sample_rate = x*1000;
+		else if(sample_rate_hint == 13)
+			decoder->private_->frame.header.sample_rate = x;
+		else
+			decoder->private_->frame.header.sample_rate = x*10;
+	}
+
+	/* read the CRC-8 byte */
+	if(!FLAC__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) {
+		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) {
+		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;
+}
+
+FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+	FLAC__uint32 x;
+	FLAC__bool wasted_bits;
+	uint32_t i;
+
+	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;
+
+	if(wasted_bits) {
+		uint32_t u;
+		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;
+		if (decoder->private_->frame.subframes[channel].wasted_bits >= bps)
+			return false;
+		bps -= decoder->private_->frame.subframes[channel].wasted_bits;
+	}
+	else
+		decoder->private_->frame.subframes[channel].wasted_bits = 0;
+
+	/*
+	 * Lots of magic numbers here
+	 */
+	if(x & 0x80) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	else if(x == 0) {
+		if(!read_subframe_constant_(decoder, channel, bps, do_full_decode))
+			return false;
+	}
+	else if(x == 2) {
+		if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode))
+			return false;
+	}
+	else if(x < 16) {
+		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) {
+		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) {
+		x = decoder->private_->frame.subframes[channel].wasted_bits;
+		for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+			uint32_t val = decoder->private_->output[channel][i];
+			decoder->private_->output[channel][i] = (val << x);
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
+	FLAC__int32 x;
+	uint32_t i;
+	FLAC__int32 *output = decoder->private_->output[channel];
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
+
+	if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+		return false; /* read_callback_ sets the state for us */
+
+	subframe->value = x;
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+			output[i] = x;
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
+	FLAC__int32 i32;
+	FLAC__uint32 u32;
+	uint32_t u;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED;
+
+	subframe->residual = decoder->private_->residual[channel];
+	subframe->order = order;
+
+	/* read warm-up samples */
+	for(u = 0; u < order; u++) {
+		if(!FLAC__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__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:
+		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 */
+			if(decoder->private_->frame.header.blocksize >> u32 < order) {
+				send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+				return true;
+			}
+			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:
+			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:
+		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:
+			FLAC__ASSERT(0);
+	}
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+		FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
+	FLAC__int32 i32;
+	FLAC__uint32 u32;
+	uint32_t u;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC;
+
+	subframe->residual = decoder->private_->residual[channel];
+	subframe->order = order;
+
+	/* read warm-up samples */
+	for(u = 0; u < order; u++) {
+		if(!FLAC__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__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) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	subframe->qlp_coeff_precision = u32+1;
+
+	/* read qlp shift */
+	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 */
+	if(i32 < 0) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	subframe->quantization_level = i32;
+
+	/* read quantized lp coefficiencts */
+	for(u = 0; u < order; u++) {
+		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__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:
+		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 */
+			if(decoder->private_->frame.header.blocksize >> u32 < order) {
+				send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+				return true;
+			}
+			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:
+			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:
+		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:
+			FLAC__ASSERT(0);
+	}
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+		if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+			if(bps <= 16 && subframe->qlp_coeff_precision <= 16)
+				decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+			else
+				decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+		else
+			decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
+	FLAC__int32 x, *residual = decoder->private_->residual[channel];
+	uint32_t i;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+	subframe->data = residual;
+
+	for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+			return false; /* read_callback_ sets the state for us */
+		residual[i] = x;
+	}
+
+	/* decode the subframe */
+	if(do_full_decode)
+		memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+
+	return true;
+}
+
+FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended)
+{
+	FLAC__uint32 rice_parameter;
+	int i;
+	uint32_t partition, sample, u;
+	const uint32_t partitions = 1u << partition_order;
+	const uint32_t partition_samples = decoder->private_->frame.header.blocksize >> partition_order;
+	const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+	const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+	/* invalid predictor and partition orders mush be handled in the callers */
+	FLAC__ASSERT(partition_order > 0? partition_samples >= predictor_order : decoder->private_->frame.header.blocksize >= predictor_order);
+
+	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;
+	}
+
+	sample = 0;
+	for(partition = 0; partition < partitions; partition++) {
+		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 < pesc) {
+			partitioned_rice_contents->raw_bits[partition] = 0;
+			u = (partition == 0) ? partition_samples - predictor_order : partition_samples;
+			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;
+		}
+		else {
+			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 == 0)? predictor_order : 0; u < partition_samples; u++, sample++) {
+				if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
+					return false; /* read_callback_ sets the state for us */
+				residual[sample] = i;
+			}
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder)
+{
+	if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+		FLAC__uint32 zero = 0;
+		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) {
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		}
+	}
+	return true;
+}
+
+FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data;
+
+	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;
+		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 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 */
+			uint32_t delta = (uint32_t)(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) {
+				uint32_t 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;
+	uint32_t approx_bytes_per_frame;
+	FLAC__bool first_seek = true;
+	const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder);
+	const uint32_t min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+	const uint32_t max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize;
+	const uint32_t max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize;
+	const uint32_t min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize;
+	/* take these from the current frame in case they've changed mid-stream */
+	uint32_t channels = FLAC__stream_decoder_get_channels(decoder);
+	uint32_t 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 calculation */
+		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)((double)(target_sample - lower_bound_sample) / (double)(upper_bound_sample - lower_bound_sample) * (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 */
+			FLAC__uint64 sample_range_16 = (upper_bound_sample - lower_bound_sample) >> 16;
+			if (sample_range_16 == 0) sample_range_16 = 1; // avoid divide by 0
+			pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) >> 8) * ((upper_bound - lower_bound) >> 8) / sample_range_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_ABORTED) {
+			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 = (uint32_t)(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 = (uint32_t)(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;
+	uint32_t 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.
+	 */
+	uint32_t 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)((double)(target_sample - left_sample) / (double)(right_sample - left_sample) * (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_ABORTED) {
+			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 {
+					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;
+}
+
+FLAC_API const void *FLAC__get_decoder_client_data(FLAC__StreamDecoder *decoder)
+{
+	return decoder->private_->client_data;
+}
diff --git a/src/libFLAC/stream_encoder.c b/src/libFLAC/stream_encoder.c
new file mode 100644
index 0000000..8bb0ef3
--- /dev/null
+++ b/src/libFLAC/stream_encoder.c
@@ -0,0 +1,4580 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 <limits.h>
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+#include <sys/types.h> /* for off_t */
+#ifdef _WIN32
+#include <windows.h> /* for GetFileType() */
+#include <io.h> /* for _get_osfhandle() */
+#endif
+#include "share/compat.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "protected/stream_encoder.h"
+#include "private/bitwriter.h"
+#include "private/bitmath.h"
+#include "private/crc.h"
+#include "private/cpu.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+#include "private/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"
+
+
+/* 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
+
+
+typedef struct {
+	FLAC__int32 *data[FLAC__MAX_CHANNELS];
+	uint32_t size; /* of each data[] in samples */
+	uint32_t tail;
+} verify_input_fifo;
+
+typedef struct {
+	const FLAC__byte *data;
+	uint32_t capacity;
+	uint32_t bytes;
+} verify_output;
+
+typedef enum {
+	ENCODER_IN_MAGIC = 0,
+	ENCODER_IN_METADATA = 1,
+	ENCODER_IN_AUDIO = 2
+} EncoderStateHint;
+
+static const  struct CompressionLevels {
+	FLAC__bool do_mid_side_stereo;
+	FLAC__bool loose_mid_side_stereo;
+	uint32_t max_lpc_order;
+	uint32_t qlp_coeff_precision;
+	FLAC__bool do_qlp_coeff_prec_search;
+	FLAC__bool do_escape_coding;
+	FLAC__bool do_exhaustive_model_search;
+	uint32_t min_residual_partition_order;
+	uint32_t max_residual_partition_order;
+	uint32_t 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
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamEncoder *encoder);
+static void free_(FLAC__StreamEncoder *encoder);
+static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, uint32_t new_blocksize);
+static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, uint32_t samples, FLAC__bool is_last_block);
+static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t 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,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	const FLAC__FrameHeader *frame_header,
+	uint32_t subframe_bps,
+	const FLAC__int32 integer_signal[],
+	FLAC__Subframe *subframe[2],
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+	FLAC__int32 *residual[2],
+	uint32_t *best_subframe,
+	uint32_t *best_bits
+);
+
+static FLAC__bool add_subframe_(
+	FLAC__StreamEncoder *encoder,
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	const FLAC__Subframe *subframe,
+	FLAC__BitWriter *frame
+);
+
+static uint32_t evaluate_constant_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal,
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	FLAC__Subframe *subframe
+);
+
+static uint32_t evaluate_fixed_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	FLAC__int32 residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	uint32_t raw_bits_per_partition[],
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	uint32_t order,
+	uint32_t rice_parameter,
+	uint32_t rice_parameter_limit,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	FLAC__bool do_escape_coding,
+	uint32_t rice_parameter_search_dist,
+	FLAC__Subframe *subframe,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+static uint32_t evaluate_lpc_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	FLAC__int32 residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	uint32_t raw_bits_per_partition[],
+	const FLAC__real lp_coeff[],
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	uint32_t order,
+	uint32_t qlp_coeff_precision,
+	uint32_t rice_parameter,
+	uint32_t rice_parameter_limit,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	FLAC__bool do_escape_coding,
+	uint32_t rice_parameter_search_dist,
+	FLAC__Subframe *subframe,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+#endif
+
+static uint32_t evaluate_verbatim_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	FLAC__Subframe *subframe
+);
+
+static uint32_t find_best_partition_order_(
+	struct FLAC__StreamEncoderPrivate *private_,
+	const FLAC__int32 residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	uint32_t raw_bits_per_partition[],
+	uint32_t residual_samples,
+	uint32_t predictor_order,
+	uint32_t rice_parameter,
+	uint32_t rice_parameter_limit,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	uint32_t bps,
+	FLAC__bool do_escape_coding,
+	uint32_t rice_parameter_search_dist,
+	FLAC__EntropyCodingMethod *best_ecm
+);
+
+static void precompute_partition_info_sums_(
+	const FLAC__int32 residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	uint32_t residual_samples,
+	uint32_t predictor_order,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	uint32_t bps
+);
+
+static void precompute_partition_info_escapes_(
+	const FLAC__int32 residual[],
+	uint32_t raw_bits_per_partition[],
+	uint32_t residual_samples,
+	uint32_t predictor_order,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order
+);
+
+static FLAC__bool set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
+	const FLAC__int32 residual[],
+#endif
+	const FLAC__uint64 abs_residual_partition_sums[],
+	const uint32_t raw_bits_per_partition[],
+	const uint32_t residual_samples,
+	const uint32_t predictor_order,
+	const uint32_t suggested_rice_parameter,
+	const uint32_t rice_parameter_limit,
+	const uint32_t rice_parameter_search_dist,
+	const uint32_t partition_order,
+	const FLAC__bool search_for_escapes,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	uint32_t *bits
+);
+
+static uint32_t get_wasted_bits_(FLAC__int32 signal[], uint32_t samples);
+
+/* verify-related routines: */
+static void append_to_verify_fifo_(
+	verify_input_fifo *fifo,
+	const FLAC__int32 * const input[],
+	uint32_t input_offset,
+	uint32_t channels,
+	uint32_t wide_samples
+);
+
+static void append_to_verify_fifo_interleaved_(
+	verify_input_fifo *fifo,
+	const FLAC__int32 input[],
+	uint32_t input_offset,
+	uint32_t channels,
+	uint32_t wide_samples
+);
+
+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__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, uint32_t samples, uint32_t current_frame, void *client_data);
+static FILE *get_binary_stdout_(void);
+
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamEncoderPrivate {
+	uint32_t 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) */
+#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
+	uint32_t subframe_bps[FLAC__MAX_CHANNELS];        /* the effective bits per sample of the input signal (stream bps - wasted bits) */
+	uint32_t subframe_bps_mid_side[2];                /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */
+	FLAC__int32 *residual_workspace[FLAC__MAX_CHANNELS][2]; /* each channel has a candidate and best workspace where the subframe residual signals will be stored */
+	FLAC__int32 *residual_workspace_mid_side[2][2];
+	FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2];
+	FLAC__Subframe subframe_workspace_mid_side[2][2];
+	FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2];
+	FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2];
+	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2];
+	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2];
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2];
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2];
+	uint32_t best_subframe[FLAC__MAX_CHANNELS];       /* index (0 or 1) into 2nd dimension of the above workspaces */
+	uint32_t best_subframe_mid_side[2];
+	uint32_t best_subframe_bits[FLAC__MAX_CHANNELS];  /* size in bits of the best subframe for each channel */
+	uint32_t best_subframe_bits_mid_side[2];
+	FLAC__uint64 *abs_residual_partition_sums;        /* workspace where the sum of abs(candidate residual) for each partition is stored */
+	uint32_t *raw_bits_per_partition;                 /* workspace where the sum of silog2(candidate residual) for each partition is stored */
+	FLAC__BitWriter *frame;                           /* the current frame being worked on */
+	uint32_t loose_mid_side_stereo_frames;            /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */
+	uint32_t loose_mid_side_stereo_frame_count;       /* number of frames using the current channel assignment */
+	FLAC__ChannelAssignment last_channel_assignment;
+	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 */
+	uint32_t current_sample_number;
+	uint32_t current_frame_number;
+	FLAC__MD5Context md5context;
+	FLAC__CPUInfo cpuinfo;
+	void (*local_precompute_partition_info_sums)(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	uint32_t (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+	uint32_t (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#else
+	uint32_t (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+	uint32_t (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], uint32_t 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[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+	void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+	void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+	void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#endif
+	FLAC__bool disable_constant_subframes;
+	FLAC__bool disable_fixed_subframes;
+	FLAC__bool disable_verbatim_subframes;
+	FLAC__bool is_ogg;
+	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;
+	uint32_t first_seekpoint_to_check;
+	FILE *file;                            /* only used when encoding to a file */
+	FLAC__uint64 bytes_written;
+	FLAC__uint64 samples_written;
+	uint32_t frames_written;
+	uint32_t 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];
+#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__uint64 *abs_residual_partition_sums_unaligned;
+	uint32_t *raw_bits_per_partition_unaligned;
+	/*
+	 * 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
+	 */
+	struct {
+		FLAC__StreamDecoder *decoder;
+		EncoderStateHint state_hint;
+		FLAC__bool needs_magic_hack;
+		verify_input_fifo input_fifo;
+		verify_output output;
+		struct {
+			FLAC__uint64 absolute_sample;
+			uint32_t frame_number;
+			uint32_t channel;
+			uint32_t sample;
+			FLAC__int32 expected;
+			FLAC__int32 got;
+		} error_stats;
+	} verify;
+	FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */
+} FLAC__StreamEncoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamEncoderStateString[] = {
+	"FLAC__STREAM_ENCODER_OK",
+	"FLAC__STREAM_ENCODER_UNINITIALIZED",
+	"FLAC__STREAM_ENCODER_OGG_ERROR",
+	"FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR",
+	"FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA",
+	"FLAC__STREAM_ENCODER_CLIENT_ERROR",
+	"FLAC__STREAM_ENCODER_IO_ERROR",
+	"FLAC__STREAM_ENCODER_FRAMING_ERROR",
+	"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_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 uint32_t OVERREAD_ = 1;
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ */
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void)
+{
+	FLAC__StreamEncoder *encoder;
+	uint32_t i;
+
+	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+	encoder = calloc(1, sizeof(FLAC__StreamEncoder));
+	if(encoder == 0) {
+		return 0;
+	}
+
+	encoder->protected_ = calloc(1, sizeof(FLAC__StreamEncoderProtected));
+	if(encoder->protected_ == 0) {
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_ = calloc(1, sizeof(FLAC__StreamEncoderPrivate));
+	if(encoder->private_ == 0) {
+		free(encoder->protected_);
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_->frame = FLAC__bitwriter_new();
+	if(encoder->private_->frame == 0) {
+		free(encoder->private_);
+		free(encoder->protected_);
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_->file = 0;
+
+	set_defaults_(encoder);
+
+	encoder->private_->is_being_deleted = false;
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0];
+		encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1];
+	}
+	for(i = 0; i < 2; i++) {
+		encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0];
+		encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1];
+	}
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0];
+		encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1];
+	}
+	for(i = 0; i < 2; i++) {
+		encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0];
+		encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1];
+	}
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
+	}
+	for(i = 0; i < 2; i++) {
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
+	}
+	for(i = 0; i < 2; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]);
+
+	encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+	return encoder;
+}
+
+FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder)
+{
+	uint32_t i;
+
+	if (encoder == NULL)
+		return ;
+
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->private_->frame);
+
+	encoder->private_->is_being_deleted = true;
+
+	(void)FLAC__stream_encoder_finish(encoder);
+
+	if(0 != encoder->private_->verify.decoder)
+		FLAC__stream_decoder_delete(encoder->private_->verify.decoder);
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
+	}
+	for(i = 0; i < 2; i++) {
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
+	}
+	for(i = 0; i < 2; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]);
+
+	FLAC__bitwriter_delete(encoder->private_->frame);
+	free(encoder->private_);
+	free(encoder->protected_);
+	free(encoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+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
+)
+{
+	uint32_t i;
+	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 FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	if(FLAC__HAS_OGG == 0 && is_ogg)
+		return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+
+	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 FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS;
+
+	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_->bits_per_sample >= 32)
+		encoder->protected_->do_mid_side_stereo = false; /* since we currently 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 FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE;
+
+	if(!FLAC__format_sample_rate_is_valid(encoder->protected_->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 FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE;
+
+	if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER)
+		return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER;
+
+	if(encoder->protected_->blocksize < encoder->protected_->max_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 = 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)
+				encoder->protected_->qlp_coeff_precision = 7;
+			else if(encoder->protected_->blocksize <= 384)
+				encoder->protected_->qlp_coeff_precision = 8;
+			else if(encoder->protected_->blocksize <= 576)
+				encoder->protected_->qlp_coeff_precision = 9;
+			else if(encoder->protected_->blocksize <= 1152)
+				encoder->protected_->qlp_coeff_precision = 10;
+			else if(encoder->protected_->blocksize <= 2304)
+				encoder->protected_->qlp_coeff_precision = 11;
+			else if(encoder->protected_->blocksize <= 4608)
+				encoder->protected_->qlp_coeff_precision = 12;
+			else
+				encoder->protected_->qlp_coeff_precision = 13;
+		}
+		else {
+			if(encoder->protected_->blocksize <= 384)
+				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2;
+			else if(encoder->protected_->blocksize <= 1152)
+				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1;
+			else
+				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
+		}
+		FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION);
+	}
+	else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION)
+		return 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_->bits_per_sample != 8 &&
+			encoder->protected_->bits_per_sample != 12 &&
+			encoder->protected_->bits_per_sample != 16 &&
+			encoder->protected_->bits_per_sample != 20 &&
+			encoder->protected_->bits_per_sample != 24
+		)
+			return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+		if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER)
+			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))
+		encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1;
+	if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order)
+		encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order;
+
+#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) {
+		uint32_t 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) {
+		uint32_t 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 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++) {
+		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 FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+			metadata_has_seektable = true;
+			if(!FLAC__format_seektable_is_legal(&m->data.seek_table))
+				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+		}
+		else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+			if(metadata_has_vorbis_comment) /* only one is allowed */
+				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+			metadata_has_vorbis_comment = true;
+		}
+		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;
+		encoder->private_->best_subframe[i] = 0;
+	}
+	for(i = 0; i < 2; i++) {
+		encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0;
+		encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0;
+		encoder->private_->best_subframe_mid_side[i] = 0;
+	}
+	encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0;
+	encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	encoder->private_->loose_mid_side_stereo_frames = (uint32_t)((double)encoder->protected_->sample_rate * 0.4 / (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 = (uint32_t)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;
+	encoder->private_->current_sample_number = 0;
+	encoder->private_->current_frame_number = 0;
+
+	/*
+	 * get the CPU info and set the function pointers
+	 */
+	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__INTEGER_ONLY_LIBRARY
+# ifndef FLAC__NO_ASM
+#if defined(FLAC__CPU_PPC64) && defined(FLAC__USE_VSX)
+#ifdef FLAC__HAS_TARGET_POWER8
+#ifdef FLAC__HAS_TARGET_POWER9
+	if (encoder->private_->cpuinfo.ppc.arch_3_00) {
+		if(encoder->protected_->max_lpc_order < 4)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_4;
+		else if(encoder->protected_->max_lpc_order < 8)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_8;
+		else if(encoder->protected_->max_lpc_order < 12)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_12;
+		else if(encoder->protected_->max_lpc_order < 16)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_16;
+		else
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+	} else
+#endif
+	if (encoder->private_->cpuinfo.ppc.arch_2_07) {
+		if(encoder->protected_->max_lpc_order < 4)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_4;
+		else if(encoder->protected_->max_lpc_order < 8)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_8;
+		else if(encoder->protected_->max_lpc_order < 12)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_12;
+		else if(encoder->protected_->max_lpc_order < 16)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_16;
+		else
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+	}
+#endif
+#endif
+	if(encoder->private_->cpuinfo.use_asm) {
+#  ifdef FLAC__CPU_IA32
+		FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+#   ifdef FLAC__HAS_NASM
+		if (encoder->private_->cpuinfo.x86.sse) {
+			if(encoder->protected_->max_lpc_order < 4)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old;
+			else if(encoder->protected_->max_lpc_order < 8)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old;
+			else if(encoder->protected_->max_lpc_order < 12)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old;
+			else if(encoder->protected_->max_lpc_order < 16)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old;
+			else
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
+		}
+		else
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
+
+		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.x86.mmx) {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx;
+		}
+		else {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+		}
+
+		if (encoder->private_->cpuinfo.x86.mmx && encoder->private_->cpuinfo.x86.cmov)
+			encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov;
+#   endif /* FLAC__HAS_NASM */
+#   if FLAC__HAS_X86INTRIN
+#    if defined FLAC__SSE_SUPPORTED
+		if (encoder->private_->cpuinfo.x86.sse) {
+			if (encoder->private_->cpuinfo.x86.sse42 || !encoder->private_->cpuinfo.x86.intel) { /* use new autocorrelation functions */
+				if(encoder->protected_->max_lpc_order < 4)
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new;
+				else if(encoder->protected_->max_lpc_order < 8)
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new;
+				else if(encoder->protected_->max_lpc_order < 12)
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new;
+				else if(encoder->protected_->max_lpc_order < 16)
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new;
+				else
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+			}
+			else { /* use old autocorrelation functions */
+				if(encoder->protected_->max_lpc_order < 4)
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old;
+				else if(encoder->protected_->max_lpc_order < 8)
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old;
+				else if(encoder->protected_->max_lpc_order < 12)
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old;
+				else if(encoder->protected_->max_lpc_order < 16)
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old;
+				else
+					encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+			}
+		}
+#    endif
+
+#    ifdef FLAC__SSE2_SUPPORTED
+		if (encoder->private_->cpuinfo.x86.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.x86.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.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
+		if (encoder->private_->cpuinfo.x86.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.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 */
+#  elif defined FLAC__CPU_X86_64
+		FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64);
+#   if FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE_SUPPORTED
+		if(encoder->private_->cpuinfo.x86.sse42 || !encoder->private_->cpuinfo.x86.intel) { /* use new autocorrelation functions */
+			if(encoder->protected_->max_lpc_order < 4)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new;
+			else if(encoder->protected_->max_lpc_order < 8)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new;
+			else if(encoder->protected_->max_lpc_order < 12)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new;
+			else if(encoder->protected_->max_lpc_order < 16)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new;
+		}
+		else {
+			if(encoder->protected_->max_lpc_order < 4)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old;
+			else if(encoder->protected_->max_lpc_order < 8)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old;
+			else if(encoder->protected_->max_lpc_order < 12)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old;
+			else if(encoder->protected_->max_lpc_order < 16)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old;
+		}
+#    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 /* !FLAC__NO_ASM */
+#endif /* !FLAC__INTEGER_ONLY_LIBRARY */
+#if !defined FLAC__NO_ASM && FLAC__HAS_X86INTRIN
+	if(encoder->private_->cpuinfo.use_asm) {
+# if defined FLAC__CPU_IA32
+#  ifdef FLAC__SSE2_SUPPORTED
+		if (encoder->private_->cpuinfo.x86.sse2)
+			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
+# 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 */
+
+	/* 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 FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_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
+	 */
+	if(encoder->protected_->verify) {
+		/*
+		 * First, set up the fifo which will hold the
+		 * original signal to compare against
+		 */
+		encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_;
+		for(i = 0; i < encoder->protected_->channels; i++) {
+			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;
+
+		/*
+		 * Now set up a stream decoder for verification
+		 */
+		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;
+			}
+		}
+
+		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;
+	encoder->private_->verify.error_stats.channel = 0;
+	encoder->private_->verify.error_stats.sample = 0;
+	encoder->private_->verify.error_stats.expected = 0;
+	encoder->private_->verify.error_stats.got = 0;
+
+	/*
+	 * 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__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 FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
+
+	/*
+	 * write the STREAMINFO metadata block
+	 */
+	if(encoder->protected_->verify)
+		encoder->private_->verify.state_hint = ENCODER_IN_METADATA;
+	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 FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
+
+	/*
+	 * Now that the STREAMINFO block is written, we can init this to an
+	 * absurdly-high value...
+	 */
+	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_->streaminfo.data.stream_info.total_samples = 0;
+
+	/*
+	 * Check to see if the supplied metadata contains a VORBIS_COMMENT;
+	 * if not, we will write an empty one (FLAC__add_metadata_block()
+	 * automatically supplies the vendor string).
+	 *
+	 * WATCHOUT: 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;
+		vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+		vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0);
+		vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */
+		vorbis_comment.data.vorbis_comment.vendor_string.length = 0;
+		vorbis_comment.data.vorbis_comment.vendor_string.entry = 0;
+		vorbis_comment.data.vorbis_comment.num_comments = 0;
+		vorbis_comment.data.vorbis_comment.comments = 0;
+		if(!FLAC__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 FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+		}
+	}
+
+	/*
+	 * write the user's metadata blocks
+	 */
+	for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+		encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1);
+		if(!FLAC__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 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 FLAC__STREAM_ENCODER_INIT_STATUS_OK;
+}
+
+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.
+	 */
+	if(GetFileType((HANDLE)_get_osfhandle(_fileno(file))) == FILE_TYPE_DISK)
+		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;
+	}
+
+	{
+		uint32_t blocksize = FLAC__stream_encoder_get_blocksize(encoder);
+
+		FLAC__ASSERT(blocksize != 0);
+		encoder->private_->total_frames_estimate = (uint32_t)((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;
+
+	if (encoder == NULL)
+		return false;
+
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+
+	if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED)
+		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;
+			if(!process_frame_(encoder, is_fractional_block, /*is_last_block=*/true))
+				error = true;
+		}
+	}
+
+	if(encoder->protected_->do_md5)
+		FLAC__MD5Final(encoder->private_->streaminfo.data.stream_info.md5sum, &encoder->private_->md5context);
+
+	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(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);
+
+	if(!error)
+		encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+	return !error;
+}
+
+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;
+#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_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;
+#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
+	encoder->protected_->verify = value;
+#endif
+	return true;
+}
+
+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_->streamable_subset = value;
+	return true;
+}
+
+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_->do_md5 = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t 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;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t 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;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t 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;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t 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, uint32_t 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;
+	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, uint32_t 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;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, uint32_t 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;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	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;
+	return true;
+}
+
+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
+	/*@@@ deprecated: */
+	encoder->protected_->do_escape_coding = value;
+#else
+	(void)value;
+#endif
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	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;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t 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;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t 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;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t 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
+	/*@@@ deprecated: */
+	encoder->protected_->rice_parameter_search_dist = value;
+#else
+	(void)value;
+#endif
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	value = flac_min(value, (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN) - 1);
+	encoder->protected_->total_samples_estimate = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t 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;
+	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;
+#endif
+	return true;
+}
+
+/*
+ * These three functions are not static, but not publicly exposed in
+ * include/FLAC/ either.  They are used by the test suite.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	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;
+	return true;
+}
+
+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;
+	return true;
+}
+
+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;
+	return true;
+}
+
+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;
+}
+
+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
+		return FLAC__STREAM_DECODER_UNINITIALIZED;
+}
+
+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
+		return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder);
+}
+
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *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)
+		*frame_number = encoder->private_->verify.error_stats.frame_number;
+	if(0 != channel)
+		*channel = encoder->private_->verify.error_stats.channel;
+	if(0 != sample)
+		*sample = encoder->private_->verify.error_stats.sample;
+	if(0 != expected)
+		*expected = encoder->private_->verify.error_stats.expected;
+	if(0 != got)
+		*got = encoder->private_->verify.error_stats.got;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	return encoder->protected_->verify;
+}
+
+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_md5(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	return encoder->protected_->do_md5;
+}
+
+FLAC_API uint32_t 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;
+}
+
+FLAC_API uint32_t 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;
+}
+
+FLAC_API uint32_t 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;
+}
+
+FLAC_API uint32_t 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 uint32_t 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;
+}
+
+FLAC_API uint32_t 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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+FLAC_API uint32_t 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;
+}
+
+FLAC_API uint32_t 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;
+}
+
+FLAC_API uint32_t 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;
+}
+
+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[], uint32_t samples)
+{
+	uint32_t i, j = 0, channel;
+	const uint32_t 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);
+
+	do {
+		const uint32_t n = flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j);
+
+		if(encoder->protected_->verify)
+			append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n);
+
+		for(channel = 0; channel < channels; channel++) {
+			if (buffer[channel] == NULL) {
+				return false;
+			}
+			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' ! */
+			}
+		}
+		else
+			j += n;
+
+		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];
+			}
+			encoder->private_->current_sample_number = 1;
+		}
+	} while(j < samples);
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples)
+{
+	uint32_t i, j, k, channel;
+	FLAC__int32 x, mid, side;
+	const uint32_t 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, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j));
+
+			/* "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;
+				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_->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, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j));
+
+			/* "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++];
+			}
+			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);
+	}
+
+	return true;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamEncoder *encoder)
+{
+	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 = 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;
+	encoder->protected_->do_exhaustive_model_search = false;
+	encoder->protected_->do_escape_coding = false;
+	encoder->protected_->min_residual_partition_order = 0;
+	encoder->protected_->max_residual_partition_order = 0;
+	encoder->protected_->rice_parameter_search_dist = 0;
+	encoder->protected_->total_samples_estimate = 0;
+	encoder->protected_->metadata = 0;
+	encoder->protected_->num_metadata_blocks = 0;
+
+	encoder->private_->seek_table = 0;
+	encoder->private_->disable_constant_subframes = false;
+	encoder->private_->disable_fixed_subframes = false;
+	encoder->private_->disable_verbatim_subframes = false;
+	encoder->private_->is_ogg = false;
+	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)
+{
+	uint32_t 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]) {
+			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]) {
+				free(encoder->private_->residual_workspace_unaligned[channel][i]);
+				encoder->private_->residual_workspace_unaligned[channel][i] = 0;
+			}
+		}
+	}
+	for(channel = 0; channel < 2; channel++) {
+		for(i = 0; i < 2; i++) {
+			if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) {
+				free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]);
+				encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0;
+			}
+		}
+	}
+	if(0 != encoder->private_->abs_residual_partition_sums_unaligned) {
+		free(encoder->private_->abs_residual_partition_sums_unaligned);
+		encoder->private_->abs_residual_partition_sums_unaligned = 0;
+	}
+	if(0 != encoder->private_->raw_bits_per_partition_unaligned) {
+		free(encoder->private_->raw_bits_per_partition_unaligned);
+		encoder->private_->raw_bits_per_partition_unaligned = 0;
+	}
+	if(encoder->protected_->verify) {
+		for(i = 0; i < encoder->protected_->channels; i++) {
+			if(0 != encoder->private_->verify.input_fifo.data[i]) {
+				free(encoder->private_->verify.input_fifo.data[i]);
+				encoder->private_->verify.input_fifo.data[i] = 0;
+			}
+		}
+	}
+	FLAC__bitwriter_free(encoder->private_->frame);
+}
+
+FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, uint32_t new_blocksize)
+{
+	FLAC__bool ok;
+	uint32_t i, channel;
+
+	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_blocksize <= encoder->private_->input_capacity)
+		return true;
+
+	ok = true;
+
+	/* 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 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_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_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_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_blocksize, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]);
+		}
+	}
+	/* 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_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_blocksize;
+	else
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+
+	return ok;
+}
+
+FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, uint32_t samples, FLAC__bool is_last_block)
+{
+	const FLAC__byte *buffer;
+	size_t bytes;
+
+	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame));
+
+	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;
+		encoder->private_->verify.output.bytes = bytes;
+		if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) {
+			encoder->private_->verify.needs_magic_hack = true;
+		}
+		else {
+			if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)
+			    || (!is_last_block
+				    && (FLAC__stream_encoder_get_verify_decoder_state(encoder) == FLAC__STREAM_DECODER_END_OF_STREAM))) {
+				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;
+			}
+		}
+	}
+
+	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__bitwriter_release_buffer(encoder->private_->frame);
+	FLAC__bitwriter_clear(encoder->private_->frame);
+
+	if(samples > 0) {
+		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__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t 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 uint32_t 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;
+		uint32_t 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 uint32_t min_framesize = metadata->data.stream_info.min_framesize;
+	const uint32_t max_framesize = metadata->data.stream_info.max_framesize;
+	const uint32_t 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 uint32_t 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 uint32_t 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 uint32_t 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) {
+		uint32_t 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;
+			uint32_t 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 uint32_t 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 uint32_t min_framesize = metadata->data.stream_info.min_framesize;
+	const uint32_t 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 uint32_t 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 > (uint32_t)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 uint32_t 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 > (uint32_t)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 uint32_t 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 > (uint32_t)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) {
+		uint32_t 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) != (uint32_t)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;
+			uint32_t 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(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;
+	}
+
+	/*
+	 * Process the frame header and subframes into the frame bitbuffer
+	 */
+	if(!process_subframes_(encoder, is_fractional_block)) {
+		/* the above function sets the state for us in case of an error */
+		return false;
+	}
+
+	/*
+	 * Zero-pad the frame to a byte_boundary
+	 */
+	if(!FLAC__bitwriter_zero_pad_to_byte_boundary(encoder->private_->frame)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	/*
+	 * CRC-16 the whole thing
+	 */
+	FLAC__ASSERT(FLAC__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, is_last_block)) {
+		/* the above function sets the state for us in case of an error */
+		return false;
+	}
+
+	/*
+	 * Get ready for the next frame
+	 */
+	encoder->private_->current_sample_number = 0;
+	encoder->private_->current_frame_number++;
+	encoder->private_->streaminfo.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize;
+
+	return true;
+}
+
+FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block)
+{
+	FLAC__FrameHeader frame_header;
+	uint32_t channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order;
+	FLAC__bool do_independent, do_mid_side;
+
+	/*
+	 * Calculate the min,max Rice partition orders
+	 */
+	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 = flac_min(max_partition_order, encoder->protected_->max_residual_partition_order);
+	}
+	min_partition_order = flac_min(min_partition_order, max_partition_order);
+
+	/*
+	 * Setup the frame
+	 */
+	frame_header.blocksize = encoder->protected_->blocksize;
+	frame_header.sample_rate = encoder->protected_->sample_rate;
+	frame_header.channels = encoder->protected_->channels;
+	frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */
+	frame_header.bits_per_sample = encoder->protected_->bits_per_sample;
+	frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+	frame_header.number.frame_number = encoder->private_->current_frame_number;
+
+	/*
+	 * Figure out what channel assignments to try
+	 */
+	if(encoder->protected_->do_mid_side_stereo) {
+		if(encoder->protected_->loose_mid_side_stereo) {
+			if(encoder->private_->loose_mid_side_stereo_frame_count == 0) {
+				do_independent = true;
+				do_mid_side = true;
+			}
+			else {
+				do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT);
+				do_mid_side = !do_independent;
+			}
+		}
+		else {
+			do_independent = true;
+			do_mid_side = true;
+		}
+	}
+	else {
+		do_independent = true;
+		do_mid_side = false;
+	}
+
+	FLAC__ASSERT(do_independent || do_mid_side);
+
+	/*
+	 * Check for wasted bits; set effective bps for each subframe
+	 */
+	if(do_independent) {
+		for(channel = 0; channel < encoder->protected_->channels; channel++) {
+			uint32_t w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
+			if (w > encoder->protected_->bits_per_sample) {
+				w = encoder->protected_->bits_per_sample;
+			}
+			encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w;
+			encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w;
+		}
+	}
+	if(do_mid_side) {
+		FLAC__ASSERT(encoder->protected_->channels == 2);
+		for(channel = 0; channel < 2; channel++) {
+			uint32_t w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
+			if (w > encoder->protected_->bits_per_sample) {
+				w = encoder->protected_->bits_per_sample;
+			}
+			encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w;
+			encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1);
+		}
+	}
+
+	/*
+	 * First do a normal encoding pass of each independent channel
+	 */
+	if(do_independent) {
+		for(channel = 0; channel < encoder->protected_->channels; channel++) {
+			if(!
+				process_subframe_(
+					encoder,
+					min_partition_order,
+					max_partition_order,
+					&frame_header,
+					encoder->private_->subframe_bps[channel],
+					encoder->private_->integer_signal[channel],
+					encoder->private_->subframe_workspace_ptr[channel],
+					encoder->private_->partitioned_rice_contents_workspace_ptr[channel],
+					encoder->private_->residual_workspace[channel],
+					encoder->private_->best_subframe+channel,
+					encoder->private_->best_subframe_bits+channel
+				)
+			)
+				return false;
+		}
+	}
+
+	/*
+	 * Now do mid and side channels if requested
+	 */
+	if(do_mid_side) {
+		FLAC__ASSERT(encoder->protected_->channels == 2);
+
+		for(channel = 0; channel < 2; channel++) {
+			if(!
+				process_subframe_(
+					encoder,
+					min_partition_order,
+					max_partition_order,
+					&frame_header,
+					encoder->private_->subframe_bps_mid_side[channel],
+					encoder->private_->integer_signal_mid_side[channel],
+					encoder->private_->subframe_workspace_ptr_mid_side[channel],
+					encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel],
+					encoder->private_->residual_workspace_mid_side[channel],
+					encoder->private_->best_subframe_mid_side+channel,
+					encoder->private_->best_subframe_bits_mid_side+channel
+				)
+			)
+				return false;
+		}
+	}
+
+	/*
+	 * Compose the frame bitbuffer
+	 */
+	if(do_mid_side) {
+		uint32_t left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */
+		FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */
+		FLAC__ChannelAssignment channel_assignment;
+
+		FLAC__ASSERT(encoder->protected_->channels == 2);
+
+		if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) {
+			channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE);
+		}
+		else {
+			uint32_t bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
+			uint32_t min_bits;
+			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 */
+			bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits         [0] + encoder->private_->best_subframe_bits         [1];
+			bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE  ] = encoder->private_->best_subframe_bits         [0] + encoder->private_->best_subframe_bits_mid_side[1];
+			bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits         [1] + encoder->private_->best_subframe_bits_mid_side[1];
+			bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE   ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1];
+
+			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 = (FLAC__ChannelAssignment)ca;
+				}
+			}
+		}
+
+		frame_header.channel_assignment = channel_assignment;
+
+		if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+			return false;
+		}
+
+		switch(channel_assignment) {
+			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+				left_subframe  = &encoder->private_->subframe_workspace         [0][encoder->private_->best_subframe         [0]];
+				right_subframe = &encoder->private_->subframe_workspace         [1][encoder->private_->best_subframe         [1]];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+				left_subframe  = &encoder->private_->subframe_workspace         [0][encoder->private_->best_subframe         [0]];
+				right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+				left_subframe  = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+				right_subframe = &encoder->private_->subframe_workspace         [1][encoder->private_->best_subframe         [1]];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+				left_subframe  = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]];
+				right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+				break;
+			default:
+				FLAC__ASSERT(0);
+		}
+
+		switch(channel_assignment) {
+			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+				left_bps  = encoder->private_->subframe_bps         [0];
+				right_bps = encoder->private_->subframe_bps         [1];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+				left_bps  = encoder->private_->subframe_bps         [0];
+				right_bps = encoder->private_->subframe_bps_mid_side[1];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+				left_bps  = encoder->private_->subframe_bps_mid_side[1];
+				right_bps = encoder->private_->subframe_bps         [1];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+				left_bps  = encoder->private_->subframe_bps_mid_side[0];
+				right_bps = encoder->private_->subframe_bps_mid_side[1];
+				break;
+			default:
+				FLAC__ASSERT(0);
+		}
+
+		/* note that encoder_add_subframe_ sets the state for us in case of an error */
+		if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame))
+			return false;
+		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->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.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;
+			}
+		}
+	}
+
+	if(encoder->protected_->loose_mid_side_stereo) {
+		encoder->private_->loose_mid_side_stereo_frame_count++;
+		if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames)
+			encoder->private_->loose_mid_side_stereo_frame_count = 0;
+	}
+
+	encoder->private_->last_channel_assignment = frame_header.channel_assignment;
+
+	return true;
+}
+
+FLAC__bool process_subframe_(
+	FLAC__StreamEncoder *encoder,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	const FLAC__FrameHeader *frame_header,
+	uint32_t subframe_bps,
+	const FLAC__int32 integer_signal[],
+	FLAC__Subframe *subframe[2],
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+	FLAC__int32 *residual[2],
+	uint32_t *best_subframe,
+	uint32_t *best_bits
+)
+{
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	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
+	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 */
+	double lpc_error[FLAC__MAX_LPC_ORDER];
+	uint32_t min_lpc_order, max_lpc_order, lpc_order;
+	uint32_t min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision;
+#endif
+	uint32_t min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order;
+	uint32_t rice_parameter;
+	uint32_t _candidate_bits, _best_bits;
+	uint32_t _best_subframe;
+	/* only use RICE2 partitions if stream bps > 16 */
+	const uint32_t 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_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+
+	if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) {
+		uint32_t signal_is_constant = false;
+		if(subframe_bps + 4 + FLAC__bitmath_ilog2((frame_header->blocksize-FLAC__MAX_FIXED_ORDER)|1) <= 32)
+			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);
+		else
+			guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor_wide(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 &&
+#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: */
+			uint32_t i;
+			signal_is_constant = true;
+			for(i = 1; i < frame_header->blocksize; i++) {
+				if(integer_signal[0] != integer_signal[i]) {
+					signal_is_constant = false;
+					break;
+				}
+			}
+		}
+		if(signal_is_constant) {
+			_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;
+			}
+		}
+		else {
+			if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) {
+				/* encode fixed */
+				if(encoder->protected_->do_exhaustive_model_search) {
+					min_fixed_order = 0;
+					max_fixed_order = FLAC__MAX_FIXED_ORDER;
+				}
+				else {
+					min_fixed_order = max_fixed_order = guess_fixed_order;
+				}
+				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++) {
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+					if(fixed_residual_bits_per_sample[fixed_order] >= (float)subframe_bps)
+						continue; /* don't even try */
+					rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > 0.0)? (uint32_t)(fixed_residual_bits_per_sample[fixed_order]+0.5) : 0; /* 0.5 is for rounding */
+#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)? (uint32_t)FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]+FLAC__FP_ONE_HALF) : 0; /* 0.5 is for rounding */
+#endif
+					rice_parameter++; /* to account for the signed->uint32_t conversion during rice coding */
+					if(rice_parameter >= rice_parameter_limit) {
+#ifndef NDEBUG
+						fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, rice_parameter_limit - 1);
+#endif
+						rice_parameter = rice_parameter_limit - 1;
+					}
+					_candidate_bits =
+						evaluate_fixed_subframe_(
+							encoder,
+							integer_signal,
+							residual[!_best_subframe],
+							encoder->private_->abs_residual_partition_sums,
+							encoder->private_->raw_bits_per_partition,
+							frame_header->blocksize,
+							subframe_bps,
+							fixed_order,
+							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 < _best_bits) {
+						_best_subframe = !_best_subframe;
+						_best_bits = _candidate_bits;
+					}
+				}
+			}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+			/* encode lpc */
+			if(encoder->protected_->max_lpc_order > 0) {
+				if(encoder->protected_->max_lpc_order >= frame_header->blocksize)
+					max_lpc_order = frame_header->blocksize-1;
+				else
+					max_lpc_order = encoder->protected_->max_lpc_order;
+				if(max_lpc_order > 0) {
+					uint32_t 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;
+							}
+							else {
+								const uint32_t guess_lpc_order =
+									FLAC__lpc_compute_best_order(
+										lpc_error,
+										max_lpc_order,
+										frame_header->blocksize,
+										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
+										)
+									);
+								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 >= (double)subframe_bps)
+									continue; /* don't even try */
+								rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (uint32_t)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */
+								rice_parameter++; /* to account for the signed->uint32_t conversion during rice coding */
+								if(rice_parameter >= rice_parameter_limit) {
+#ifndef NDEBUG
+									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(+1bps for side channel) streams */
+									if(subframe_bps <= 17) {
+										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 */
+		}
+	}
+
+	/* 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_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+	}
+
+	*best_subframe = _best_subframe;
+	*best_bits = _best_bits;
+
+	return true;
+}
+
+FLAC__bool add_subframe_(
+	FLAC__StreamEncoder *encoder,
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	const FLAC__Subframe *subframe,
+	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_FRAMING_ERROR;
+				return false;
+			}
+			break;
+		case FLAC__SUBFRAME_TYPE_FIXED:
+			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), 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), blocksize, subframe_bps, subframe->wasted_bits, frame)) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+				return false;
+			}
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+
+	return true;
+}
+
+#define SPOTCHECK_ESTIMATE 0
+#if SPOTCHECK_ESTIMATE
+static void spotcheck_subframe_estimate_(
+	FLAC__StreamEncoder *encoder,
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	const FLAC__Subframe *subframe,
+	uint32_t 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 uint32_t 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
+
+uint32_t evaluate_constant_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal,
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	FLAC__Subframe *subframe
+)
+{
+	uint32_t estimate;
+	subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT;
+	subframe->data.constant.value = signal;
+
+	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;
+}
+
+uint32_t evaluate_fixed_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	FLAC__int32 residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	uint32_t raw_bits_per_partition[],
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	uint32_t order,
+	uint32_t rice_parameter,
+	uint32_t rice_parameter_limit,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	FLAC__bool do_escape_coding,
+	uint32_t rice_parameter_search_dist,
+	FLAC__Subframe *subframe,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+	uint32_t i, residual_bits, estimate;
+	const uint32_t residual_samples = blocksize - order;
+
+	FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual);
+
+	subframe->type = FLAC__SUBFRAME_TYPE_FIXED;
+
+	subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
+	subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
+	subframe->data.fixed.residual = residual;
+
+	residual_bits =
+		find_best_partition_order_(
+			encoder->private_,
+			residual,
+			abs_residual_partition_sums,
+			raw_bits_per_partition,
+			residual_samples,
+			order,
+			rice_parameter,
+			rice_parameter_limit,
+			min_partition_order,
+			max_partition_order,
+			subframe_bps,
+			do_escape_coding,
+			rice_parameter_search_dist,
+			&subframe->data.fixed.entropy_coding_method
+		);
+
+	subframe->data.fixed.order = order;
+	for(i = 0; i < order; i++)
+		subframe->data.fixed.warmup[i] = signal[i];
+
+	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
+uint32_t evaluate_lpc_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	FLAC__int32 residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	uint32_t raw_bits_per_partition[],
+	const FLAC__real lp_coeff[],
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	uint32_t order,
+	uint32_t qlp_coeff_precision,
+	uint32_t rice_parameter,
+	uint32_t rice_parameter_limit,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	FLAC__bool do_escape_coding,
+	uint32_t rice_parameter_search_dist,
+	FLAC__Subframe *subframe,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+	FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; /* WATCHOUT: the size is important; some x86 intrinsic routines need more than lpc order elements */
+	uint32_t i, residual_bits, estimate;
+	int quantization, ret;
+	const uint32_t residual_samples = blocksize - order;
+
+	/* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps(+1bps for side channel) streams */
+	if(subframe_bps <= 17) {
+		FLAC__ASSERT(order > 0);
+		FLAC__ASSERT(order <= FLAC__MAX_LPC_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);
+	if(ret != 0)
+		return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */
+
+	if(subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+		if(subframe_bps <= 16 && qlp_coeff_precision <= 16)
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+		else
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+	else
+		encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+
+	subframe->type = FLAC__SUBFRAME_TYPE_LPC;
+
+	subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
+	subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
+	subframe->data.lpc.residual = residual;
+
+	residual_bits =
+		find_best_partition_order_(
+			encoder->private_,
+			residual,
+			abs_residual_partition_sums,
+			raw_bits_per_partition,
+			residual_samples,
+			order,
+			rice_parameter,
+			rice_parameter_limit,
+			min_partition_order,
+			max_partition_order,
+			subframe_bps,
+			do_escape_coding,
+			rice_parameter_search_dist,
+			&subframe->data.lpc.entropy_coding_method
+		);
+
+	subframe->data.lpc.order = order;
+	subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision;
+	subframe->data.lpc.quantization_level = quantization;
+	memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(FLAC__int32)*FLAC__MAX_LPC_ORDER);
+	for(i = 0; i < order; i++)
+		subframe->data.lpc.warmup[i] = signal[i];
+
+	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
+
+uint32_t evaluate_verbatim_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	uint32_t blocksize,
+	uint32_t subframe_bps,
+	FLAC__Subframe *subframe
+)
+{
+	uint32_t estimate;
+
+	subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+	subframe->data.verbatim.data = signal;
+
+	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;
+}
+
+uint32_t find_best_partition_order_(
+	FLAC__StreamEncoderPrivate *private_,
+	const FLAC__int32 residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	uint32_t raw_bits_per_partition[],
+	uint32_t residual_samples,
+	uint32_t predictor_order,
+	uint32_t rice_parameter,
+	uint32_t rice_parameter_limit,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	uint32_t bps,
+	FLAC__bool do_escape_coding,
+	uint32_t rice_parameter_search_dist,
+	FLAC__EntropyCodingMethod *best_ecm
+)
+{
+	uint32_t residual_bits, best_residual_bits = 0;
+	uint32_t best_parameters_index = 0;
+	uint32_t best_partition_order = 0;
+	const uint32_t blocksize = residual_samples + predictor_order;
+
+	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 = flac_min(min_partition_order, max_partition_order);
+
+	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;
+		uint32_t sum;
+
+		for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) {
+			if(!
+				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,
+					(uint32_t)partition_order,
+					do_escape_coding,
+					&private_->partitioned_rice_contents_extra[!best_parameters_index],
+					&residual_bits
+				)
+			)
+			{
+				FLAC__ASSERT(best_residual_bits != 0);
+				break;
+			}
+			sum += 1u << partition_order;
+			if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
+				best_residual_bits = residual_bits;
+				best_parameters_index = !best_parameters_index;
+				best_partition_order = partition_order;
+			}
+		}
+	}
+
+	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;
+		uint32_t 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(uint32_t)*(1<<(best_partition_order)));
+		if(do_escape_coding)
+			memcpy(prc->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(uint32_t)*(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;
+			}
+		}
+	}
+
+	return best_residual_bits;
+}
+
+void precompute_partition_info_sums_(
+	const FLAC__int32 residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	uint32_t residual_samples,
+	uint32_t predictor_order,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order,
+	uint32_t bps
+)
+{
+	const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+	uint32_t partitions = 1u << max_partition_order;
+
+	FLAC__ASSERT(default_partition_samples > predictor_order);
+
+	/* first do max_partition_order */
+	{
+		const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
+		uint32_t partition, residual_sample, end = (uint32_t)(-(int)predictor_order);
+		/* WATCHOUT: "bps + FLAC__MAX_EXTRA_RESIDUAL_BPS" is the maximum assumed size of the average residual magnitude */
+		if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				FLAC__uint32 abs_residual_partition_sum = 0;
+				end += default_partition_samples;
+				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 */
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				FLAC__uint64 abs_residual_partition_sum64 = 0;
+				end += default_partition_samples;
+				for( ; residual_sample < end; residual_sample++)
+					abs_residual_partition_sum64 += 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_sum64;
+			}
+		}
+	}
+
+	/* now merge partitions for lower orders */
+	{
+		uint32_t 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--) {
+			uint32_t 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;
+			}
+		}
+	}
+}
+
+void precompute_partition_info_escapes_(
+	const FLAC__int32 residual[],
+	uint32_t raw_bits_per_partition[],
+	uint32_t residual_samples,
+	uint32_t predictor_order,
+	uint32_t min_partition_order,
+	uint32_t max_partition_order
+)
+{
+	int partition_order;
+	uint32_t from_partition, to_partition = 0;
+	const uint32_t blocksize = residual_samples + predictor_order;
+
+	/* first do max_partition_order */
+	for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) {
+		FLAC__int32 r;
+		FLAC__uint32 rmax;
+		uint32_t partition, partition_sample, partition_samples, residual_sample;
+		const uint32_t partitions = 1u << partition_order;
+		const uint32_t default_partition_samples = blocksize >> partition_order;
+
+		FLAC__ASSERT(default_partition_samples > predictor_order);
+
+		for(partition = residual_sample = 0; partition < partitions; partition++) {
+			partition_samples = default_partition_samples;
+			if(partition == 0)
+				partition_samples -= predictor_order;
+			rmax = 0;
+			for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) {
+				r = residual[residual_sample++];
+				/* OPT: maybe faster: rmax |= r ^ (r>>31) */
+				if(r < 0)
+					rmax |= ~r;
+				else
+					rmax |= r;
+			}
+			/* 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; /*@@@ yuck, should remove the 'for' loop instead */
+	}
+
+	/* now merge partitions for lower orders */
+	for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) {
+		uint32_t m;
+		uint32_t i;
+		const uint32_t partitions = 1u << partition_order;
+		for(i = 0; i < partitions; i++) {
+			m = raw_bits_per_partition[from_partition];
+			from_partition++;
+			raw_bits_per_partition[to_partition] = flac_max(m, raw_bits_per_partition[from_partition]);
+			from_partition++;
+			to_partition++;
+		}
+	}
+}
+
+#ifdef EXACT_RICE_BITS_CALCULATION
+static inline uint32_t count_rice_bits_in_partition_(
+	const uint32_t rice_parameter,
+	const uint32_t partition_samples,
+	const FLAC__int32 *residual
+)
+{
+	uint32_t 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
+static inline uint32_t count_rice_bits_in_partition_(
+	const uint32_t rice_parameter,
+	const uint32_t partition_samples,
+	const FLAC__uint64 abs_residual_partition_sum
+)
+{
+	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?
+				(uint32_t)(abs_residual_partition_sum >> (rice_parameter-1)) /* rice_parameter-1 because the real coder sign-folds instead of using a sign bit */
+				: (uint32_t)(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
+
+FLAC__bool set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
+	const FLAC__int32 residual[],
+#endif
+	const FLAC__uint64 abs_residual_partition_sums[],
+	const uint32_t raw_bits_per_partition[],
+	const uint32_t residual_samples,
+	const uint32_t predictor_order,
+	const uint32_t suggested_rice_parameter,
+	const uint32_t rice_parameter_limit,
+	const uint32_t rice_parameter_search_dist,
+	const uint32_t partition_order,
+	const FLAC__bool search_for_escapes,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	uint32_t *bits
+)
+{
+	uint32_t rice_parameter, partition_bits;
+	uint32_t best_partition_bits, best_rice_parameter = 0;
+	uint32_t bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
+	uint32_t *parameters, *raw_bits;
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+	uint32_t min_rice_parameter, max_rice_parameter;
+#else
+	(void)rice_parameter_search_dist;
+#endif
+
+	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, flac_max(6u, partition_order));
+	parameters = partitioned_rice_contents->parameters;
+	raw_bits = partitioned_rice_contents->raw_bits;
+
+	if(partition_order == 0) {
+		best_partition_bits = (uint32_t)(-1);
+#ifdef ENABLE_RICE_PARAMETER_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 >= rice_parameter_limit) {
+#ifndef NDEBUG
+				fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, rice_parameter_limit - 1);
+#endif
+				max_rice_parameter = rice_parameter_limit - 1;
+			}
+		}
+		else
+			min_rice_parameter = max_rice_parameter = suggested_rice_parameter;
+
+		for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#else
+			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 = count_rice_bits_in_partition_(rice_parameter, residual_samples, abs_residual_partition_sums[0]);
+#endif
+			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) {
+			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 = 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 {
+		uint32_t partition, residual_sample;
+		uint32_t partition_samples;
+		FLAC__uint64 mean, k;
+		const uint32_t partitions = 1u << partition_order;
+		for(partition = residual_sample = 0; partition < partitions; partition++) {
+			partition_samples = (residual_samples+predictor_order) >> partition_order;
+			if(partition == 0) {
+				if(partition_samples <= predictor_order)
+					return false;
+				else
+					partition_samples -= predictor_order;
+			}
+			mean = abs_residual_partition_sums[partition];
+			/* 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
+				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) {
+#ifndef NDEBUG
+				fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, rice_parameter_limit - 1);
+#endif
+				rice_parameter = rice_parameter_limit - 1;
+			}
+
+			best_partition_bits = (uint32_t)(-1);
+#ifdef ENABLE_RICE_PARAMETER_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 >= rice_parameter_limit) {
+#ifndef NDEBUG
+					fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, rice_parameter_limit - 1);
+#endif
+					max_rice_parameter = rice_parameter_limit - 1;
+				}
+			}
+			else
+				min_rice_parameter = max_rice_parameter = rice_parameter;
+
+			for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#endif
+#ifdef EXACT_RICE_BITS_CALCULATION
+				partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, residual+residual_sample);
+#else
+				partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, abs_residual_partition_sums[partition]);
+#endif
+				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) {
+				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 = 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;
+		}
+	}
+
+	*bits = bits_;
+	return true;
+}
+
+uint32_t get_wasted_bits_(FLAC__int32 signal[], uint32_t samples)
+{
+	uint32_t i, shift;
+	FLAC__int32 x = 0;
+
+	for(i = 0; i < samples && !(x&1); i++)
+		x |= signal[i];
+
+	if(x == 0) {
+		shift = 0;
+	}
+	else {
+		for(shift = 0; !(x&1); shift++)
+			x >>= 1;
+	}
+
+	if(shift > 0) {
+		for(i = 0; i < samples; i++)
+			 signal[i] >>= shift;
+	}
+
+	return shift;
+}
+
+void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], uint32_t input_offset, uint32_t channels, uint32_t wide_samples)
+{
+	uint32_t channel;
+
+	for(channel = 0; channel < channels; channel++)
+		memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples);
+
+	fifo->tail += wide_samples;
+
+	FLAC__ASSERT(fifo->tail <= fifo->size);
+}
+
+void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], uint32_t input_offset, uint32_t channels, uint32_t wide_samples)
+{
+	uint32_t channel;
+	uint32_t sample, wide_sample;
+	uint32_t tail = fifo->tail;
+
+	sample = input_offset * channels;
+	for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+		for(channel = 0; channel < channels; channel++)
+			fifo->data[channel][tail] = input[sample++];
+		tail++;
+	}
+	fifo->tail = tail;
+
+	FLAC__ASSERT(fifo->tail <= fifo->size);
+}
+
+FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
+	const size_t encoded_bytes = encoder->private_->verify.output.bytes;
+	(void)decoder;
+
+	if(encoder->private_->verify.needs_magic_hack) {
+		FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH);
+		*bytes = FLAC__STREAM_SYNC_LENGTH;
+		memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes);
+		encoder->private_->verify.needs_magic_hack = false;
+	}
+	else {
+		if(encoded_bytes == 0) {
+			/*
+			 * If we get here, a FIFO underflow has occurred,
+			 * which means there is a bug somewhere.
+			 */
+			FLAC__ASSERT(0);
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		}
+		else if(encoded_bytes < *bytes)
+			*bytes = encoded_bytes;
+		memcpy(buffer, encoder->private_->verify.output.data, *bytes);
+		encoder->private_->verify.output.data += *bytes;
+		encoder->private_->verify.output.bytes -= *bytes;
+	}
+
+	return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data;
+	uint32_t channel;
+	const uint32_t channels = frame->header.channels;
+	const uint32_t blocksize = frame->header.blocksize;
+	const uint32_t 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)) {
+			uint32_t i, sample = 0;
+			FLAC__int32 expect = 0, got = 0;
+
+			for(i = 0; i < blocksize; i++) {
+				if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) {
+					sample = i;
+					expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i];
+					got = (FLAC__int32)buffer[channel][i];
+					break;
+				}
+			}
+			FLAC__ASSERT(i < blocksize);
+			FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+			encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample;
+			encoder->private_->verify.error_stats.frame_number = (uint32_t)(frame->header.number.sample_number / blocksize);
+			encoder->private_->verify.error_stats.channel = channel;
+			encoder->private_->verify.error_stats.sample = sample;
+			encoder->private_->verify.error_stats.expected = expect;
+			encoder->private_->verify.error_stats.got = got;
+			encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+	/* dequeue the frame from the fifo */
+	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;
+}
+
+void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	(void)decoder, (void)metadata, (void)client_data;
+}
+
+void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
+	(void)decoder, (void)status;
+	encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+}
+
+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, uint32_t samples, uint32_t 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 __EMX__
+	setmode(fileno(stdout), O_BINARY);
+#endif
+
+	return stdout;
+}
diff --git a/src/libFLAC/stream_encoder_framing.c b/src/libFLAC/stream_encoder_framing.c
new file mode 100644
index 0000000..2c78916
--- /dev/null
+++ b/src/libFLAC/stream_encoder_framing.c
@@ -0,0 +1,554 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 <stdio.h>
+#include <string.h> /* for strlen() */
+#include "private/stream_encoder_framing.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+#include "share/compat.h"
+
+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 uint32_t residual_samples, const uint32_t predictor_order, const uint32_t rice_parameters[], const uint32_t raw_bits[], const uint32_t partition_order, const FLAC__bool is_extended);
+
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw)
+{
+	uint32_t i, j;
+	const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING);
+
+	if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN))
+		return false;
+
+	if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN))
+		return false;
+
+	/*
+	 * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string
+	 */
+	i = metadata->length;
+	if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+		FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry);
+		i -= metadata->data.vorbis_comment.vendor_string.length;
+		i += vendor_string_length;
+	}
+	FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+	/* double protection */
+	if(i >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+		return false;
+	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__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__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__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__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__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__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__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+				return false;
+			FLAC__ASSERT(metadata->data.stream_info.total_samples < (FLAC__U64L(1) << 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__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16))
+				return false;
+			break;
+		case FLAC__METADATA_TYPE_PADDING:
+			if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8))
+				return false;
+			break;
+		case FLAC__METADATA_TYPE_APPLICATION:
+			if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))
+				return false;
+			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__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+					return false;
+				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__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__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length))
+				return false;
+			if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length))
+				return false;
+			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__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length))
+					return false;
+				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__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__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+				return false;
+			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__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+				return false;
+			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__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+					return false;
+				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__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+					return false;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+					return false;
+				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 *indx = track->indices + j;
+
+					if(!FLAC__bitwriter_write_raw_uint64(bw, indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+						return false;
+					if(!FLAC__bitwriter_write_raw_uint32(bw, indx->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+						return false;
+					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__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length))
+				return false;
+			break;
+	}
+
+	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
+	return true;
+}
+
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw)
+{
+	uint32_t u, blocksize_hint, sample_rate_hint;
+	FLAC__byte crc;
+
+	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
+
+	if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
+		return false;
+
+	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);
+	blocksize_hint = 0;
+	switch(header->blocksize) {
+		case   192: u = 1; break;
+		case   576: u = 2; break;
+		case  1152: u = 3; break;
+		case  2304: u = 4; break;
+		case  4608: u = 5; break;
+		case   256: u = 8; break;
+		case   512: u = 9; break;
+		case  1024: u = 10; break;
+		case  2048: u = 11; break;
+		case  4096: u = 12; break;
+		case  8192: u = 13; break;
+		case 16384: u = 14; break;
+		case 32768: u = 15; break;
+		default:
+			if(header->blocksize <= 0x100)
+				blocksize_hint = u = 6;
+			else
+				blocksize_hint = u = 7;
+			break;
+	}
+	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  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;
+			else if(header->sample_rate % 10 == 0)
+				sample_rate_hint = u = 14;
+			else if(header->sample_rate <= 0xffff)
+				sample_rate_hint = u = 13;
+			else
+				u = 0;
+			break;
+	}
+	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);
+	switch(header->channel_assignment) {
+		case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+			u = header->channels - 1;
+			break;
+		case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+			FLAC__ASSERT(header->channels == 2);
+			u = 8;
+			break;
+		case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+			FLAC__ASSERT(header->channels == 2);
+			u = 9;
+			break;
+		case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+			FLAC__ASSERT(header->channels == 2);
+			u = 10;
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+	if(!FLAC__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));
+	switch(header->bits_per_sample) {
+		case 8 : u = 1; break;
+		case 12: u = 2; break;
+		case 16: u = 4; break;
+		case 20: u = 5; break;
+		case 24: u = 6; break;
+		default: u = 0; break;
+	}
+	if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN))
+		return false;
+
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN))
+		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__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16))
+			return false;
+
+	switch(sample_rate_hint) {
+		case 12:
+			if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8))
+				return false;
+			break;
+		case 13:
+			if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16))
+				return false;
+			break;
+		case 14:
+			if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16))
+				return false;
+			break;
+	}
+
+	/* write the CRC */
+	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, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw)
+{
+	FLAC__bool ok;
+
+	ok =
+		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, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw)
+{
+	uint32_t i;
+
+	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__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+			return false;
+
+	for(i = 0; i < subframe->order; i++)
+		if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
+			return false;
+
+	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:
+		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:
+			FLAC__ASSERT(0);
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw)
+{
+	uint32_t i;
+
+	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__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+			return false;
+
+	for(i = 0; i < subframe->order; i++)
+		if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
+			return false;
+
+	if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+		return false;
+	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__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision))
+			return false;
+
+	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:
+		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:
+			FLAC__ASSERT(0);
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, uint32_t samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw)
+{
+	uint32_t i;
+	const FLAC__int32 *signal = subframe->data;
+
+	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__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+			return false;
+
+	for(i = 0; i < samples; i++)
+		if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps))
+			return false;
+
+	return true;
+}
+
+FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method)
+{
+	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:
+		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:
+			FLAC__ASSERT(0);
+	}
+	return true;
+}
+
+FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const uint32_t residual_samples, const uint32_t predictor_order, const uint32_t rice_parameters[], const uint32_t raw_bits[], const uint32_t partition_order, const FLAC__bool is_extended)
+{
+	const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+	const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+	if(partition_order == 0) {
+		uint32_t i;
+
+		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 {
+			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__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0]))
+					return false;
+			}
+		}
+		return true;
+	}
+	else {
+		uint32_t i, j, k = 0, k_last = 0;
+		uint32_t partition_samples;
+		const uint32_t default_partition_samples = (residual_samples+predictor_order) >> partition_order;
+		for(i = 0; i < (1u<<partition_order); i++) {
+			partition_samples = default_partition_samples;
+			if(i == 0)
+				partition_samples -= predictor_order;
+			k += partition_samples;
+			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__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__bitwriter_write_raw_int32(bw, residual[j], raw_bits[i]))
+						return false;
+				}
+			}
+			k_last = k;
+		}
+		return true;
+	}
+}
diff --git a/src/libFLAC/stream_encoder_intrin_avx2.c b/src/libFLAC/stream_encoder_intrin_avx2.c
new file mode 100644
index 0000000..94bde0e
--- /dev/null
+++ b/src/libFLAC/stream_encoder_intrin_avx2.c
@@ -0,0 +1,146 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/stream_encoder.h"
+#include "private/bitmath.h"
+#ifdef FLAC__AVX2_SUPPORTED
+
+#include <stdlib.h>    /* for abs() */
+#include <immintrin.h> /* AVX2 */
+#include "FLAC/assert.h"
+
+FLAC__SSE_TARGET("avx2")
+void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+		uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps)
+{
+	const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+	uint32_t partitions = 1u << max_partition_order;
+
+	FLAC__ASSERT(default_partition_samples > predictor_order);
+
+	/* first do max_partition_order */
+	{
+		const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
+		uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order);
+
+		if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				__m256i sum256 = _mm256_setzero_si256();
+				__m128i sum128;
+				end += default_partition_samples;
+
+				for( ; (int)residual_sample < (int)end-7; residual_sample+=8) {
+					__m256i res256 = _mm256_abs_epi32(_mm256_loadu_si256((const __m256i*)(residual+residual_sample)));
+					sum256 = _mm256_add_epi32(sum256, res256);
+				}
+
+				sum128 = _mm_add_epi32(_mm256_extracti128_si256(sum256, 1), _mm256_castsi256_si128(sum256));
+
+				for( ; (int)residual_sample < (int)end-3; residual_sample+=4) {
+					__m128i res128 = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(residual+residual_sample)));
+					sum128 = _mm_add_epi32(sum128, res128);
+				}
+
+				for( ; residual_sample < end; residual_sample++) {
+					__m128i res128 = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+					sum128 = _mm_add_epi32(sum128, res128);
+				}
+
+				sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_SHUFFLE(1,0,3,2)));
+				sum128 = _mm_add_epi32(sum128, _mm_shufflelo_epi16(sum128, _MM_SHUFFLE(1,0,3,2)));
+				abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(sum128);
+/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */
+#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64)
+				abs_residual_partition_sums[partition] &= 0xFFFFFFFF; /**/
+#endif
+			}
+		}
+		else { /* have to pessimistically use 64 bits for accumulator */
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				__m256i sum256 = _mm256_setzero_si256();
+				__m128i sum128;
+				end += default_partition_samples;
+
+				for( ; (int)residual_sample < (int)end-3; residual_sample+=4) {
+					__m128i res128 = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(residual+residual_sample)));
+					__m256i res256 = _mm256_cvtepu32_epi64(res128);
+					sum256 = _mm256_add_epi64(sum256, res256);
+				}
+
+				sum128 = _mm_add_epi64(_mm256_extracti128_si256(sum256, 1), _mm256_castsi256_si128(sum256));
+
+				for( ; (int)residual_sample < (int)end-1; residual_sample+=2) {
+					__m128i res128 = _mm_abs_epi32(_mm_loadl_epi64((const __m128i*)(residual+residual_sample)));
+					res128 = _mm_cvtepu32_epi64(res128);
+					sum128 = _mm_add_epi64(sum128, res128);
+				}
+
+				for( ; residual_sample < end; residual_sample++) {
+					__m128i res128 = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+					sum128 = _mm_add_epi64(sum128, res128);
+				}
+
+				sum128 = _mm_add_epi64(sum128, _mm_srli_si128(sum128, 8));
+				_mm_storel_epi64((__m128i*)(abs_residual_partition_sums+partition), sum128);
+			}
+		}
+	}
+
+	/* now merge partitions for lower orders */
+	{
+		uint32_t 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--) {
+			uint32_t 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;
+			}
+		}
+	}
+	_mm256_zeroupper();
+}
+
+#endif /* FLAC__AVX2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
diff --git a/src/libFLAC/stream_encoder_intrin_sse2.c b/src/libFLAC/stream_encoder_intrin_sse2.c
new file mode 100644
index 0000000..44ee4d3
--- /dev/null
+++ b/src/libFLAC/stream_encoder_intrin_sse2.c
@@ -0,0 +1,159 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/stream_encoder.h"
+#include "private/bitmath.h"
+#ifdef FLAC__SSE2_SUPPORTED
+
+#include <stdlib.h>    /* for abs() */
+#include <emmintrin.h> /* SSE2 */
+#include "FLAC/assert.h"
+#include "share/compat.h"
+
+FLAC__SSE_TARGET("sse2")
+static inline __m128i local_abs_epi32(__m128i val)
+{
+	__m128i mask = _mm_srai_epi32(val, 31);
+	val = _mm_xor_si128(val, mask);
+	val = _mm_sub_epi32(val, mask);
+	return val;
+}
+
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+		uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps)
+{
+	const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+	uint32_t partitions = 1u << max_partition_order;
+
+	FLAC__ASSERT(default_partition_samples > predictor_order);
+
+	/* first do max_partition_order */
+	{
+		const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
+		uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order);
+
+		if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				__m128i mm_sum = _mm_setzero_si128();
+				uint32_t e1, e3;
+				end += default_partition_samples;
+
+				e1 = (residual_sample + 3) & ~3; e3 = end & ~3;
+				if(e1 > end)
+					e1 = end; /* try flac -l 1 -b 16 and you'll be here */
+
+				/* assumption: residual[] is properly aligned so (residual + e1) is properly aligned too and _mm_loadu_si128() is fast */
+				for( ; residual_sample < e1; residual_sample++) {
+					__m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+					mm_sum = _mm_add_epi32(mm_sum, mm_res);
+				}
+
+				for( ; residual_sample < e3; residual_sample+=4) {
+					__m128i mm_res = local_abs_epi32(_mm_loadu_si128((const __m128i*)(residual+residual_sample)));
+					mm_sum = _mm_add_epi32(mm_sum, mm_res);
+				}
+
+				for( ; residual_sample < end; residual_sample++) {
+					__m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+					mm_sum = _mm_add_epi32(mm_sum, mm_res);
+				}
+
+				mm_sum = _mm_add_epi32(mm_sum, _mm_shuffle_epi32(mm_sum, _MM_SHUFFLE(1,0,3,2)));
+				mm_sum = _mm_add_epi32(mm_sum, _mm_shufflelo_epi16(mm_sum, _MM_SHUFFLE(1,0,3,2)));
+				abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(mm_sum);
+/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */
+#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64)
+				abs_residual_partition_sums[partition] &= 0xFFFFFFFF;
+#endif
+			}
+		}
+		else { /* have to pessimistically use 64 bits for accumulator */
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				__m128i mm_sum = _mm_setzero_si128();
+				uint32_t e1, e3;
+				end += default_partition_samples;
+
+				e1 = (residual_sample + 1) & ~1; e3 = end & ~1;
+				FLAC__ASSERT(e1 <= end);
+
+				for( ; residual_sample < e1; residual_sample++) {
+					__m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); /*  0   0   0  |r0|  ==   00   |r0_64| */
+					mm_sum = _mm_add_epi64(mm_sum, mm_res);
+				}
+
+				for( ; residual_sample < e3; residual_sample+=2) {
+					__m128i mm_res = local_abs_epi32(_mm_loadl_epi64((const __m128i*)(residual+residual_sample))); /*  0   0  |r1|   |r0| */
+					mm_res = _mm_shuffle_epi32(mm_res, _MM_SHUFFLE(3,1,2,0)); /* 0  |r1|  0  |r0|  ==  |r1_64|  |r0_64|  */
+					mm_sum = _mm_add_epi64(mm_sum, mm_res);
+				}
+
+				for( ; residual_sample < end; residual_sample++) {
+					__m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+					mm_sum = _mm_add_epi64(mm_sum, mm_res);
+				}
+
+				mm_sum = _mm_add_epi64(mm_sum, _mm_srli_si128(mm_sum, 8));
+				_mm_storel_epi64((__m128i*)(abs_residual_partition_sums+partition), mm_sum);
+			}
+		}
+	}
+
+	/* now merge partitions for lower orders */
+	{
+		uint32_t 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--) {
+			uint32_t 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;
+			}
+		}
+	}
+}
+
+#endif /* FLAC__SSE2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
diff --git a/src/libFLAC/stream_encoder_intrin_ssse3.c b/src/libFLAC/stream_encoder_intrin_ssse3.c
new file mode 100644
index 0000000..d384dc0
--- /dev/null
+++ b/src/libFLAC/stream_encoder_intrin_ssse3.c
@@ -0,0 +1,148 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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/cpu.h"
+
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/stream_encoder.h"
+#include "private/bitmath.h"
+#ifdef FLAC__SSSE3_SUPPORTED
+
+#include <stdlib.h>    /* for abs() */
+#include <tmmintrin.h> /* SSSE3 */
+#include "FLAC/assert.h"
+
+FLAC__SSE_TARGET("ssse3")
+void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+		uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps)
+{
+	const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+	uint32_t partitions = 1u << max_partition_order;
+
+	FLAC__ASSERT(default_partition_samples > predictor_order);
+
+	/* first do max_partition_order */
+	{
+		const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
+		uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order);
+
+		if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				__m128i mm_sum = _mm_setzero_si128();
+				uint32_t e1, e3;
+				end += default_partition_samples;
+
+				e1 = (residual_sample + 3) & ~3; e3 = end & ~3;
+				if(e1 > end)
+					e1 = end; /* try flac -l 1 -b 16 and you'll be here */
+
+				/* assumption: residual[] is properly aligned so (residual + e1) is properly aligned too and _mm_loadu_si128() is fast */
+				for( ; residual_sample < e1; residual_sample++) {
+					__m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+					mm_sum = _mm_add_epi32(mm_sum, mm_res);
+				}
+
+				for( ; residual_sample < e3; residual_sample+=4) {
+					__m128i mm_res = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(residual+residual_sample)));
+					mm_sum = _mm_add_epi32(mm_sum, mm_res);
+				}
+
+				for( ; residual_sample < end; residual_sample++) {
+					__m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+					mm_sum = _mm_add_epi32(mm_sum, mm_res);
+				}
+
+				mm_sum = _mm_add_epi32(mm_sum, _mm_shuffle_epi32(mm_sum, _MM_SHUFFLE(1,0,3,2)));
+				mm_sum = _mm_add_epi32(mm_sum, _mm_shufflelo_epi16(mm_sum, _MM_SHUFFLE(1,0,3,2)));
+				abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(mm_sum);
+/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */
+#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64)
+				abs_residual_partition_sums[partition] &= 0xFFFFFFFF;
+#endif
+			}
+		}
+		else { /* have to pessimistically use 64 bits for accumulator */
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				__m128i mm_sum = _mm_setzero_si128();
+				uint32_t e1, e3;
+				end += default_partition_samples;
+
+				e1 = (residual_sample + 1) & ~1; e3 = end & ~1;
+				FLAC__ASSERT(e1 <= end);
+
+				for( ; residual_sample < e1; residual_sample++) {
+					__m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); /*  0   0   0  |r0|  ==   00   |r0_64| */
+					mm_sum = _mm_add_epi64(mm_sum, mm_res);
+				}
+
+				for( ; residual_sample < e3; residual_sample+=2) {
+					__m128i mm_res = _mm_abs_epi32(_mm_loadl_epi64((const __m128i*)(residual+residual_sample))); /*  0   0  |r1|   |r0| */
+					mm_res = _mm_shuffle_epi32(mm_res, _MM_SHUFFLE(3,1,2,0)); /* 0  |r1|  0  |r0|  ==  |r1_64|  |r0_64|  */
+					mm_sum = _mm_add_epi64(mm_sum, mm_res);
+				}
+
+				for( ; residual_sample < end; residual_sample++) {
+					__m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+					mm_sum = _mm_add_epi64(mm_sum, mm_res);
+				}
+
+				mm_sum = _mm_add_epi64(mm_sum, _mm_srli_si128(mm_sum, 8));
+				_mm_storel_epi64((__m128i*)(abs_residual_partition_sums+partition), mm_sum);
+			}
+		}
+	}
+
+	/* now merge partitions for lower orders */
+	{
+		uint32_t 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--) {
+			uint32_t 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;
+			}
+		}
+	}
+}
+
+#endif /* FLAC__SSSE3_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
diff --git a/src/libFLAC/window.c b/src/libFLAC/window.c
new file mode 100644
index 0000000..94495f3
--- /dev/null
+++ b/src/libFLAC/window.c
@@ -0,0 +1,282 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 * fabsf((float)n/(float)N-0.5f) - 0.38f * cosf(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 * cosf(2.0f * M_PI * n / N) + 0.08f * cosf(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 * cosf(2.0f * M_PI * n / N) + 0.14128f * cosf(4.0f * M_PI * n / N) - 0.01168f * cosf(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)(0.21557895f - 0.41663158f * cosf(2.0f * M_PI * n / N) + 0.277263158f * cosf(4.0f * M_PI * n / N) - 0.083578947f * cosf(6.0f * M_PI * n / N) + 0.006947368f * cosf(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 * cosf(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 * cosf(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 * cosf(2.0f * M_PI * n / N) + 0.098f * cosf(4.0f * M_PI * n / N) - 0.001f * cosf(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*cosf(2.0f*M_PI*n/N) + 0.1365995f*cosf(4.0f*M_PI*n/N) - 0.0106411f*cosf(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 * cosf(M_PI * n / Np));
+				window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cosf(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 * cosf(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 * cosf(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 * cosf(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 * cosf(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 * cosf(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 * cosf(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 */
diff --git a/src/libFLAC/windows_unicode_filenames.c b/src/libFLAC/windows_unicode_filenames.c
new file mode 100644
index 0000000..bf3bfe1
--- /dev/null
+++ b/src/libFLAC/windows_unicode_filenames.c
@@ -0,0 +1,187 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016  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 <io.h>
+#include <windows.h>
+#include "share/windows_unicode_filenames.h"
+
+/*** FIXME: KLUDGE: export these syms for flac.exe, metaflac.exe, etc. ***/
+
+/* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */
+static wchar_t *wchar_from_utf8(const char *str)
+{
+	wchar_t *widestr;
+	int len;
+
+	if (!str)
+		return NULL;
+	if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0)
+		return NULL;
+	if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) == NULL)
+		return NULL;
+	if (MultiByteToWideChar(CP_UTF8, 0, str, -1, widestr, len) == 0) {
+		free(widestr);
+		widestr = NULL;
+	}
+
+	return widestr;
+}
+
+
+static FLAC__bool utf8_filenames = false;
+
+
+FLAC_API void flac_internal_set_utf8_filenames(FLAC__bool flag)
+{
+	utf8_filenames = flag ? true : false;
+}
+
+FLAC_API FLAC__bool flac_internal_get_utf8_filenames(void)
+{
+	return utf8_filenames;
+}
+
+/* file functions */
+
+FLAC_API FILE* flac_internal_fopen_utf8(const char *filename, const char *mode)
+{
+	if (!utf8_filenames) {
+		return fopen(filename, mode);
+	} else {
+		wchar_t *wname = NULL;
+		wchar_t *wmode = NULL;
+		FILE *f = NULL;
+
+		do {
+			if (!(wname = wchar_from_utf8(filename))) break;
+			if (!(wmode = wchar_from_utf8(mode))) break;
+			f = _wfopen(wname, wmode);
+		} while(0);
+
+		free(wname);
+		free(wmode);
+
+		return f;
+	}
+}
+
+FLAC_API int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer)
+{
+	if (!utf8_filenames) {
+		return _stat64(path, buffer);
+	} else {
+		wchar_t *wpath;
+		int ret;
+
+		if (!(wpath = wchar_from_utf8(path))) return -1;
+		ret = _wstat64(wpath, buffer);
+		free(wpath);
+
+		return ret;
+	}
+}
+
+FLAC_API int flac_internal_chmod_utf8(const char *filename, int pmode)
+{
+	if (!utf8_filenames) {
+		return _chmod(filename, pmode);
+	} else {
+		wchar_t *wname;
+		int ret;
+
+		if (!(wname = wchar_from_utf8(filename))) return -1;
+		ret = _wchmod(wname, pmode);
+		free(wname);
+
+		return ret;
+	}
+}
+
+FLAC_API int flac_internal_utime_utf8(const char *filename, struct utimbuf *times)
+{
+	if (!utf8_filenames) {
+		return utime(filename, times);
+	} else {
+		wchar_t *wname;
+		struct __utimbuf64 ut;
+		int ret;
+
+		if (!(wname = wchar_from_utf8(filename))) return -1;
+		ut.actime = times->actime;
+		ut.modtime = times->modtime;
+		ret = _wutime64(wname, &ut);
+		free(wname);
+
+		return ret;
+	}
+}
+
+FLAC_API int flac_internal_unlink_utf8(const char *filename)
+{
+	if (!utf8_filenames) {
+		return _unlink(filename);
+	} else {
+		wchar_t *wname;
+		int ret;
+
+		if (!(wname = wchar_from_utf8(filename))) return -1;
+		ret = _wunlink(wname);
+		free(wname);
+
+		return ret;
+	}
+}
+
+FLAC_API int flac_internal_rename_utf8(const char *oldname, const char *newname)
+{
+	if (!utf8_filenames) {
+		return rename(oldname, newname);
+	} else {
+		wchar_t *wold = NULL;
+		wchar_t *wnew = NULL;
+		int ret = -1;
+
+		do {
+			if (!(wold = wchar_from_utf8(oldname))) break;
+			if (!(wnew = wchar_from_utf8(newname))) break;
+			ret = _wrename(wold, wnew);
+		} while(0);
+
+		free(wold);
+		free(wnew);
+
+		return ret;
+	}
+}
diff --git a/src/metaflac/CMakeLists.txt b/src/metaflac/CMakeLists.txt
new file mode 100644
index 0000000..677ab1a
--- /dev/null
+++ b/src/metaflac/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_executable(metaflac
+    main.c
+    operations.c
+    operations_shorthand_cuesheet.c
+    operations_shorthand_picture.c
+    operations_shorthand_seektable.c
+    operations_shorthand_streaminfo.c
+    operations_shorthand_vorbiscomment.c
+    options.c
+    usage.c
+    utils.c
+    $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+    $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(metaflac FLAC getopt utf8)
+
+install(TARGETS metaflac EXPORT targets
+    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
diff --git a/src/metaflac/Makefile.am b/src/metaflac/Makefile.am
new file mode 100644
index 0000000..3393ec8
--- /dev/null
+++ b/src/metaflac/Makefile.am
@@ -0,0 +1,61 @@
+#  metaflac - Command-line FLAC metadata editor
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+bin_PROGRAMS = metaflac
+
+AM_CFLAGS = @OGG_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	metaflac.vcproj \
+	metaflac.vcxproj \
+	metaflac.vcxproj.filters
+
+metaflac_SOURCES = \
+	main.c \
+	operations.c \
+	operations_shorthand_cuesheet.c \
+	operations_shorthand_picture.c \
+	operations_shorthand_seektable.c \
+	operations_shorthand_streaminfo.c \
+	operations_shorthand_vorbiscomment.c \
+	options.c \
+	usage.c \
+	utils.c \
+	operations.h \
+	operations_shorthand.h \
+	options.h \
+	usage.h \
+	utils.h
+metaflac_LDFLAGS = $(AM_LDFLAGS)
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+metaflac_LDADD = \
+	$(top_builddir)/src/share/grabbag/libgrabbag.la \
+	$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+	$(top_builddir)/src/share/getopt/libgetopt.la \
+	$(top_builddir)/src/share/utf8/libutf8.la \
+	$(top_builddir)/src/libFLAC/libFLAC.la \
+	$(win_utf8_lib) \
+	@LTLIBICONV@
+
+CLEANFILES = metaflac.exe
diff --git a/src/metaflac/Makefile.lite b/src/metaflac/Makefile.lite
new file mode 100644
index 0000000..7025717
--- /dev/null
+++ b/src/metaflac/Makefile.lite
@@ -0,0 +1,56 @@
+#  metaflac - Command-line FLAC metadata editor
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = metaflac
+
+INCLUDES = -I./include -I$(topdir)/include $(OGG_INCLUDES)
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libFLAC.a $(libdir)/libreplaygain_analysis.a $(libdir)/libgetopt.a $(libdir)/libutf8.a $(OGG_EXPLICIT_LIBS) $(ICONV_LIBS) -lm
+else
+ifeq ($(findstring Windows,$(OS)),Windows)
+    LIBS = -lgrabbag -lFLAC -lreplaygain_analysis -lgetopt -lutf8 -lgrabbag -lwin_utf8_io $(OGG_LIBS) -lm
+else
+    LIBS = -lgrabbag -lFLAC -lreplaygain_analysis -lgetopt -lutf8 -lgrabbag $(OGG_LIBS) -lm
+endif
+endif
+
+SRCS_C = \
+	main.c \
+	operations.c \
+	operations_shorthand_cuesheet.c \
+	operations_shorthand_picture.c \
+	operations_shorthand_seektable.c \
+	operations_shorthand_streaminfo.c \
+	operations_shorthand_vorbiscomment.c \
+	options.c \
+	usage.c \
+	utils.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/metaflac/main.c b/src/metaflac/main.c
new file mode 100644
index 0000000..8c5d5ee
--- /dev/null
+++ b/src/metaflac/main.c
@@ -0,0 +1,71 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "operations.h"
+#include "options.h"
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+
+int main(int argc, char *argv[])
+{
+	CommandLineOptions options;
+	int ret = 0;
+
+#ifdef __EMX__
+	_response(&argc, &argv);
+	_wildcard(&argc, &argv);
+#endif
+#ifdef _WIN32
+	if (get_utf8_argv(&argc, &argv) != 0) {
+		fputs("ERROR: failed to convert command line parameters to UTF-8\n", stderr);
+		return 1;
+	}
+#endif
+
+#ifdef _WIN32
+	{
+		const char *var;
+		var = getenv("LC_ALL");
+		if (!var)
+			var = getenv("LC_NUMERIC");
+		if (!var)
+			var = getenv("LANG");
+		if (!var || strcmp(var, "C") != 0)
+			setlocale(LC_ALL, "");
+	}
+#else
+	setlocale(LC_ALL, "");
+#endif
+	init_options(&options);
+
+	if ((ret = parse_options(argc, argv, &options)) == 0)
+		ret = !do_operations(&options);
+	else
+		ret = 1;
+
+	free_options(&options);
+
+	return ret;
+}
diff --git a/src/metaflac/metaflac.vcproj b/src/metaflac/metaflac.vcproj
new file mode 100644
index 0000000..81259be
--- /dev/null
+++ b/src/metaflac/metaflac.vcproj
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="metaflac"

+	ProjectGUID="{4cefbc87-c215-11db-8314-0800200c9a66}"

+	RootNamespace="metaflac"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\operations.h"

+				>

+			</File>

+			<File

+				RelativePath=".\options.h"

+				>

+			</File>

+			<File

+				RelativePath=".\usage.h"

+				>

+			</File>

+			<File

+				RelativePath=".\utils.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+			<File

+				RelativePath=".\operations.c"

+				>

+			</File>

+			<File

+				RelativePath=".\operations_shorthand_cuesheet.c"

+				>

+			</File>

+			<File

+				RelativePath=".\operations_shorthand_picture.c"

+				>

+			</File>

+			<File

+				RelativePath=".\operations_shorthand_seektable.c"

+				>

+			</File>

+			<File

+				RelativePath=".\operations_shorthand_streaminfo.c"

+				>

+			</File>

+			<File

+				RelativePath=".\operations_shorthand_vorbiscomment.c"

+				>

+			</File>

+			<File

+				RelativePath=".\options.c"

+				>

+			</File>

+			<File

+				RelativePath=".\usage.c"

+				>

+			</File>

+			<File

+				RelativePath=".\utils.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/metaflac/metaflac.vcxproj b/src/metaflac/metaflac.vcxproj
new file mode 100644
index 0000000..54d584f
--- /dev/null
+++ b/src/metaflac/metaflac.vcxproj
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc87-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>metaflac</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="operations.h" />

+    <ClInclude Include="options.h" />

+    <ClInclude Include="usage.h" />

+    <ClInclude Include="utils.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c" />

+    <ClCompile Include="operations.c" />

+    <ClCompile Include="operations_shorthand_cuesheet.c" />

+    <ClCompile Include="operations_shorthand_picture.c" />

+    <ClCompile Include="operations_shorthand_seektable.c" />

+    <ClCompile Include="operations_shorthand_streaminfo.c" />

+    <ClCompile Include="operations_shorthand_vorbiscomment.c" />

+    <ClCompile Include="options.c" />

+    <ClCompile Include="usage.c" />

+    <ClCompile Include="utils.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\getopt\getopt_static.vcxproj">

+      <Project>{4cefbc80-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\grabbag\grabbag_static.vcxproj">

+      <Project>{4cefbc81-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\replaygain_analysis\replaygain_analysis_static.vcxproj">

+      <Project>{4cefbc89-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\utf8\utf8_static.vcxproj">

+      <Project>{4cefbc92-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\win_utf8_io\win_utf8_io_static.vcxproj">

+      <Project>{4cefbe02-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/metaflac/metaflac.vcxproj.filters b/src/metaflac/metaflac.vcxproj.filters
new file mode 100644
index 0000000..763405d
--- /dev/null
+++ b/src/metaflac/metaflac.vcxproj.filters
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="operations.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="options.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="usage.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="utils.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="operations.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="operations_shorthand_cuesheet.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="operations_shorthand_picture.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="operations_shorthand_seektable.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="operations_shorthand_streaminfo.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="operations_shorthand_vorbiscomment.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="options.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="usage.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="utils.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/metaflac/operations.c b/src/metaflac/operations.c
new file mode 100644
index 0000000..952f1d6
--- /dev/null
+++ b/src/metaflac/operations.c
@@ -0,0 +1,673 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "operations.h"
+#include "usage.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "operations_shorthand.h"
+
+static void show_version(void);
+static FLAC__bool do_major_operation(const CommandLineOptions *options);
+static FLAC__bool do_major_operation_on_file(const char *filename, const CommandLineOptions *options);
+static FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
+static FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
+static FLAC__bool do_major_operation__remove(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
+static FLAC__bool do_major_operation__remove_all(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
+static FLAC__bool do_shorthand_operations(const CommandLineOptions *options);
+static FLAC__bool do_shorthand_operations_on_file(const char *filename, const CommandLineOptions *options);
+static FLAC__bool do_shorthand_operation(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool utf8_convert);
+static FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime, FLAC__bool scan);
+static FLAC__bool do_shorthand_operation__add_padding(const char *filename, FLAC__Metadata_Chain *chain, unsigned length, FLAC__bool *needs_write);
+
+static FLAC__bool passes_filter(const CommandLineOptions *options, const FLAC__StreamMetadata *block, unsigned block_number);
+static void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned block_number, FLAC__bool raw, FLAC__bool hexdump_application);
+
+/* from operations_shorthand_seektable.c */
+extern FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write);
+
+/* from operations_shorthand_streaminfo.c */
+extern FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+
+/* from operations_shorthand_vorbiscomment.c */
+extern FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw);
+
+/* from operations_shorthand_cuesheet.c */
+extern FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+
+/* from operations_shorthand_picture.c */
+extern FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+
+
+FLAC__bool do_operations(const CommandLineOptions *options)
+{
+	FLAC__bool ok = true;
+
+	if(options->show_long_help) {
+		long_usage(0);
+	}
+	if(options->show_version) {
+		show_version();
+	}
+	else if(options->args.checks.num_major_ops > 0) {
+		FLAC__ASSERT(options->args.checks.num_shorthand_ops == 0);
+		FLAC__ASSERT(options->args.checks.num_major_ops == 1);
+		FLAC__ASSERT(options->args.checks.num_major_ops == options->ops.num_operations);
+		ok = do_major_operation(options);
+	}
+	else if(options->args.checks.num_shorthand_ops > 0) {
+		FLAC__ASSERT(options->args.checks.num_shorthand_ops == options->ops.num_operations);
+		ok = do_shorthand_operations(options);
+	}
+
+	return ok;
+}
+
+/*
+ * local routines
+ */
+
+void show_version(void)
+{
+	printf("metaflac %s\n", FLAC__VERSION_STRING);
+}
+
+FLAC__bool do_major_operation(const CommandLineOptions *options)
+{
+	unsigned i;
+	FLAC__bool ok = true;
+
+	/* to die after first error,     v---  add '&& ok' here */
+	for(i = 0; i < options->num_files; i++)
+		ok &= do_major_operation_on_file(options->filenames[i], options);
+
+	return ok;
+}
+
+FLAC__bool do_major_operation_on_file(const char *filename, const CommandLineOptions *options)
+{
+	FLAC__bool ok = true, needs_write = false, is_ogg = false;
+	FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
+
+	if(0 == chain)
+		die("out of memory allocating chain");
+
+	/*@@@@ lame way of guessing the file type */
+	if(strlen(filename) >= 4 && (0 == strcmp(filename+strlen(filename)-4, ".oga") || 0 == strcmp(filename+strlen(filename)-4, ".ogg")))
+		is_ogg = true;
+
+	if(! (is_ogg? FLAC__metadata_chain_read_ogg(chain, filename) : FLAC__metadata_chain_read(chain, filename)) ) {
+		print_error_with_chain_status(chain, "%s: ERROR: reading metadata", filename);
+		FLAC__metadata_chain_delete(chain);
+		return false;
+	}
+
+	switch(options->ops.operations[0].type) {
+		case OP__LIST:
+			ok = do_major_operation__list(options->prefix_with_filename? filename : 0, chain, options);
+			break;
+		case OP__APPEND:
+			ok = do_major_operation__append(chain, options);
+			needs_write = true;
+			break;
+		case OP__REMOVE:
+			ok = do_major_operation__remove(chain, options);
+			needs_write = true;
+			break;
+		case OP__REMOVE_ALL:
+			ok = do_major_operation__remove_all(chain, options);
+			needs_write = true;
+			break;
+		case OP__MERGE_PADDING:
+			FLAC__metadata_chain_merge_padding(chain);
+			needs_write = true;
+			break;
+		case OP__SORT_PADDING:
+			FLAC__metadata_chain_sort_padding(chain);
+			needs_write = true;
+			break;
+		default:
+			FLAC__ASSERT(0);
+			return false;
+	}
+
+	if(ok && needs_write) {
+		if(options->use_padding)
+			FLAC__metadata_chain_sort_padding(chain);
+		ok = FLAC__metadata_chain_write(chain, options->use_padding, options->preserve_modtime);
+		if(!ok)
+			print_error_with_chain_status(chain, "%s: ERROR: writing FLAC file", filename);
+	}
+
+	FLAC__metadata_chain_delete(chain);
+
+	return ok;
+}
+
+FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
+{
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+	FLAC__StreamMetadata *block;
+	FLAC__bool ok = true;
+	unsigned block_number;
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	block_number = 0;
+	do {
+		block = FLAC__metadata_iterator_get_block(iterator);
+		ok &= (0 != block);
+		if(!ok)
+			flac_fprintf(stderr, "%s: ERROR: couldn't get block from chain\n", filename);
+		else if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number))
+			write_metadata(filename, block, block_number, !options->utf8_convert, options->application_data_format_is_hexdump);
+		block_number++;
+	} while(ok && FLAC__metadata_iterator_next(iterator));
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	return ok;
+}
+
+FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
+{
+	(void) chain, (void) options;
+	flac_fprintf(stderr, "ERROR: --append not implemented yet\n");
+	return false;
+}
+
+FLAC__bool do_major_operation__remove(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
+{
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+	FLAC__bool ok = true;
+	unsigned block_number;
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	block_number = 0;
+	while(ok && FLAC__metadata_iterator_next(iterator)) {
+		block_number++;
+		if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number)) {
+			ok &= FLAC__metadata_iterator_delete_block(iterator, options->use_padding);
+			if(options->use_padding)
+				ok &= FLAC__metadata_iterator_next(iterator);
+		}
+	}
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	return ok;
+}
+
+FLAC__bool do_major_operation__remove_all(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
+{
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+	FLAC__bool ok = true;
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	while(ok && FLAC__metadata_iterator_next(iterator)) {
+		ok &= FLAC__metadata_iterator_delete_block(iterator, options->use_padding);
+		if(options->use_padding)
+			ok &= FLAC__metadata_iterator_next(iterator);
+	}
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	return ok;
+}
+
+FLAC__bool do_shorthand_operations(const CommandLineOptions *options)
+{
+	unsigned i;
+	FLAC__bool ok = true;
+
+	/* to die after first error,     v---  add '&& ok' here */
+	for(i = 0; i < options->num_files; i++)
+		ok &= do_shorthand_operations_on_file(options->filenames[i], options);
+
+	/* check if OP__ADD_REPLAY_GAIN requested */
+	if(ok && options->num_files > 0) {
+		for(i = 0; i < options->ops.num_operations; i++) {
+			if(options->ops.operations[i].type == OP__ADD_REPLAY_GAIN)
+				ok = do_shorthand_operation__add_replay_gain(options->filenames, options->num_files, options->preserve_modtime, false);
+			else if(options->ops.operations[i].type == OP__SCAN_REPLAY_GAIN)
+				ok = do_shorthand_operation__add_replay_gain(options->filenames, options->num_files, options->preserve_modtime, true);
+		}
+	}
+
+	return ok;
+}
+
+FLAC__bool do_shorthand_operations_on_file(const char *filename, const CommandLineOptions *options)
+{
+	unsigned i;
+	FLAC__bool ok = true, needs_write = false, use_padding = options->use_padding;
+	FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
+
+	if(0 == chain)
+		die("out of memory allocating chain");
+
+	if(!FLAC__metadata_chain_read(chain, filename)) {
+		print_error_with_chain_status(chain, "%s: ERROR: reading metadata", filename);
+		ok = false;
+		goto cleanup;
+	}
+
+	for(i = 0; i < options->ops.num_operations && ok; i++) {
+		/*
+		 * Do OP__ADD_SEEKPOINT last to avoid decoding twice if both
+		 * --add-seekpoint and --import-cuesheet-from are used.
+		 */
+		if(options->ops.operations[i].type != OP__ADD_SEEKPOINT)
+			ok &= do_shorthand_operation(filename, options->prefix_with_filename, chain, &options->ops.operations[i], &needs_write, options->utf8_convert);
+
+		/* The following seems counterintuitive but the meaning
+		 * of 'use_padding' is 'try to keep the overall metadata
+		 * to its original size, adding or truncating extra
+		 * padding if necessary' which is why we need to turn it
+		 * off in this case.  If we don't, the extra padding block
+		 * will just be truncated.
+		 */
+		if(options->ops.operations[i].type == OP__ADD_PADDING)
+			use_padding = false;
+	}
+
+	/*
+	 * Do OP__ADD_SEEKPOINT last to avoid decoding twice if both
+	 * --add-seekpoint and --import-cuesheet-from are used.
+	 */
+	for(i = 0; i < options->ops.num_operations && ok; i++) {
+		if(options->ops.operations[i].type == OP__ADD_SEEKPOINT)
+			ok &= do_shorthand_operation(filename, options->prefix_with_filename, chain, &options->ops.operations[i], &needs_write, options->utf8_convert);
+	}
+
+	if(ok && needs_write) {
+		if(use_padding)
+			FLAC__metadata_chain_sort_padding(chain);
+		ok = FLAC__metadata_chain_write(chain, use_padding, options->preserve_modtime);
+		if(!ok)
+			print_error_with_chain_status(chain, "%s: ERROR: writing FLAC file", filename);
+	}
+
+  cleanup :
+	FLAC__metadata_chain_delete(chain);
+
+	return ok;
+}
+
+FLAC__bool do_shorthand_operation(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool utf8_convert)
+{
+	FLAC__bool ok = true;
+
+	switch(operation->type) {
+		case OP__SHOW_MD5SUM:
+		case OP__SHOW_MIN_BLOCKSIZE:
+		case OP__SHOW_MAX_BLOCKSIZE:
+		case OP__SHOW_MIN_FRAMESIZE:
+		case OP__SHOW_MAX_FRAMESIZE:
+		case OP__SHOW_SAMPLE_RATE:
+		case OP__SHOW_CHANNELS:
+		case OP__SHOW_BPS:
+		case OP__SHOW_TOTAL_SAMPLES:
+		case OP__SET_MD5SUM:
+		case OP__SET_MIN_BLOCKSIZE:
+		case OP__SET_MAX_BLOCKSIZE:
+		case OP__SET_MIN_FRAMESIZE:
+		case OP__SET_MAX_FRAMESIZE:
+		case OP__SET_SAMPLE_RATE:
+		case OP__SET_CHANNELS:
+		case OP__SET_BPS:
+		case OP__SET_TOTAL_SAMPLES:
+			ok = do_shorthand_operation__streaminfo(filename, prefix_with_filename, chain, operation, needs_write);
+			break;
+		case OP__SHOW_VC_VENDOR:
+		case OP__SHOW_VC_FIELD:
+		case OP__REMOVE_VC_ALL:
+		case OP__REMOVE_VC_FIELD:
+		case OP__REMOVE_VC_FIRSTFIELD:
+		case OP__SET_VC_FIELD:
+		case OP__IMPORT_VC_FROM:
+		case OP__EXPORT_VC_TO:
+			ok = do_shorthand_operation__vorbis_comment(filename, prefix_with_filename, chain, operation, needs_write, !utf8_convert);
+			break;
+		case OP__IMPORT_CUESHEET_FROM:
+		case OP__EXPORT_CUESHEET_TO:
+			ok = do_shorthand_operation__cuesheet(filename, chain, operation, needs_write);
+			break;
+		case OP__IMPORT_PICTURE_FROM:
+		case OP__EXPORT_PICTURE_TO:
+			ok = do_shorthand_operation__picture(filename, chain, operation, needs_write);
+			break;
+		case OP__ADD_SEEKPOINT:
+			ok = do_shorthand_operation__add_seekpoints(filename, chain, operation->argument.add_seekpoint.specification, needs_write);
+			break;
+		case OP__ADD_REPLAY_GAIN:
+		case OP__SCAN_REPLAY_GAIN:
+			/* these commands are always executed last */
+			ok = true;
+			break;
+		case OP__ADD_PADDING:
+			ok = do_shorthand_operation__add_padding(filename, chain, operation->argument.add_padding.length, needs_write);
+			break;
+		default:
+			ok = false;
+			FLAC__ASSERT(0);
+			break;
+	};
+
+	return ok;
+}
+
+FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime, FLAC__bool scan)
+{
+	FLAC__StreamMetadata streaminfo;
+	float *title_gains = 0, *title_peaks = 0;
+	float album_gain, album_peak;
+	unsigned sample_rate = 0;
+	unsigned bits_per_sample = 0;
+	unsigned channels = 0;
+	unsigned i;
+	const char *error;
+	FLAC__bool first = true;
+
+	FLAC__ASSERT(num_files > 0);
+
+	for(i = 0; i < num_files; i++) {
+		FLAC__ASSERT(0 != filenames[i]);
+		if(!FLAC__metadata_get_streaminfo(filenames[i], &streaminfo)) {
+			flac_fprintf(stderr, "%s: ERROR: can't open file or get STREAMINFO block\n", filenames[i]);
+			return false;
+		}
+		if(first) {
+			first = false;
+			sample_rate = streaminfo.data.stream_info.sample_rate;
+			bits_per_sample = streaminfo.data.stream_info.bits_per_sample;
+			channels = streaminfo.data.stream_info.channels;
+		}
+		else {
+			if(sample_rate != streaminfo.data.stream_info.sample_rate) {
+				flac_fprintf(stderr, "%s: ERROR: sample rate of %u Hz does not match previous files' %u Hz\n", filenames[i], streaminfo.data.stream_info.sample_rate, sample_rate);
+				return false;
+			}
+			if(bits_per_sample != streaminfo.data.stream_info.bits_per_sample) {
+				flac_fprintf(stderr, "%s: ERROR: resolution of %u bps does not match previous files' %u bps\n", filenames[i], streaminfo.data.stream_info.bits_per_sample, bits_per_sample);
+				return false;
+			}
+			if(channels != streaminfo.data.stream_info.channels) {
+				flac_fprintf(stderr, "%s: ERROR: # channels (%u) does not match previous files' (%u)\n", filenames[i], streaminfo.data.stream_info.channels, channels);
+				return false;
+			}
+		}
+		if(!grabbag__replaygain_is_valid_sample_frequency(sample_rate)) {
+			flac_fprintf(stderr, "%s: ERROR: sample rate of %u Hz is not supported\n", filenames[i], sample_rate);
+			return false;
+		}
+		if(channels != 1 && channels != 2) {
+			flac_fprintf(stderr, "%s: ERROR: # of channels (%u) is not supported, must be 1 or 2\n", filenames[i], channels);
+			return false;
+		}
+	}
+	FLAC__ASSERT(bits_per_sample >= FLAC__MIN_BITS_PER_SAMPLE && bits_per_sample <= FLAC__MAX_BITS_PER_SAMPLE);
+
+	if(!grabbag__replaygain_init(sample_rate)) {
+		FLAC__ASSERT(0);
+		/* double protection */
+		flac_fprintf(stderr, "internal error\n");
+		return false;
+	}
+
+	if(
+		0 == (title_gains = safe_malloc_mul_2op_(sizeof(float), /*times*/num_files)) ||
+		0 == (title_peaks = safe_malloc_mul_2op_(sizeof(float), /*times*/num_files))
+	)
+		die("out of memory allocating space for title gains/peaks");
+
+	for(i = 0; i < num_files; i++) {
+		if(0 != (error = grabbag__replaygain_analyze_file(filenames[i], title_gains+i, title_peaks+i))) {
+			flac_fprintf(stderr, "%s: ERROR: during analysis (%s)\n", filenames[i], error);
+			free(title_gains);
+			free(title_peaks);
+			return false;
+		}
+	}
+	grabbag__replaygain_get_album(&album_gain, &album_peak);
+
+	for(i = 0; i < num_files; i++) {
+		if(!scan) {
+			if(0 != (error = grabbag__replaygain_store_to_file(filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i], preserve_modtime))) {
+				flac_fprintf(stderr, "%s: ERROR: writing tags (%s)\n", filenames[i], error);
+				free(title_gains);
+				free(title_peaks);
+				return false;
+			}
+		} else {
+			flac_fprintf(stdout, "%s: %f %f %f %f\n", filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i]);
+		}
+	}
+
+	free(title_gains);
+	free(title_peaks);
+	return true;
+}
+
+FLAC__bool do_shorthand_operation__add_padding(const char *filename, FLAC__Metadata_Chain *chain, unsigned length, FLAC__bool *needs_write)
+{
+	FLAC__StreamMetadata *padding = 0;
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	while(FLAC__metadata_iterator_next(iterator))
+		;
+
+	padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+	if(0 == padding)
+		die("out of memory allocating PADDING block");
+
+	padding->length = length;
+
+	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding)) {
+		print_error_with_chain_status(chain, "%s: ERROR: adding new PADDING block to metadata", filename);
+		FLAC__metadata_object_delete(padding);
+		FLAC__metadata_iterator_delete(iterator);
+		return false;
+	}
+
+	FLAC__metadata_iterator_delete(iterator);
+	*needs_write = true;
+	return true;
+}
+
+FLAC__bool passes_filter(const CommandLineOptions *options, const FLAC__StreamMetadata *block, unsigned block_number)
+{
+	unsigned i, j;
+	FLAC__bool matches_number = false, matches_type = false;
+	FLAC__bool has_block_number_arg = false;
+
+	for(i = 0; i < options->args.num_arguments; i++) {
+		if(options->args.arguments[i].type == ARG__BLOCK_TYPE || options->args.arguments[i].type == ARG__EXCEPT_BLOCK_TYPE) {
+			for(j = 0; j < options->args.arguments[i].value.block_type.num_entries; j++) {
+				if(options->args.arguments[i].value.block_type.entries[j].type == block->type) {
+					if(block->type != FLAC__METADATA_TYPE_APPLICATION || !options->args.arguments[i].value.block_type.entries[j].filter_application_by_id || 0 == memcmp(options->args.arguments[i].value.block_type.entries[j].application_id, block->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))
+						matches_type = true;
+				}
+			}
+		}
+		else if(options->args.arguments[i].type == ARG__BLOCK_NUMBER) {
+			has_block_number_arg = true;
+			for(j = 0; j < options->args.arguments[i].value.block_number.num_entries; j++) {
+				if(options->args.arguments[i].value.block_number.entries[j] == block_number)
+					matches_number = true;
+			}
+		}
+	}
+
+	if(!has_block_number_arg)
+		matches_number = true;
+
+	if(options->args.checks.has_block_type) {
+		FLAC__ASSERT(!options->args.checks.has_except_block_type);
+	}
+	else if(options->args.checks.has_except_block_type)
+		matches_type = !matches_type;
+	else
+		matches_type = true;
+
+	return matches_number && matches_type;
+}
+
+void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned block_number, FLAC__bool raw, FLAC__bool hexdump_application)
+{
+	unsigned i, j;
+
+/*@@@ yuck, should do this with a varargs function or something: */
+#define PPR if(filename) { if(raw) printf("%s:",filename); else flac_printf("%s:",filename); }
+	PPR; printf("METADATA block #%u\n", block_number);
+	PPR; printf("  type: %u (%s)\n", (unsigned)block->type, block->type < FLAC__METADATA_TYPE_UNDEFINED? FLAC__MetadataTypeString[block->type] : "UNKNOWN");
+	PPR; printf("  is last: %s\n", block->is_last? "true":"false");
+	PPR; printf("  length: %u\n", block->length);
+
+	switch(block->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			PPR; printf("  minimum blocksize: %u samples\n", block->data.stream_info.min_blocksize);
+			PPR; printf("  maximum blocksize: %u samples\n", block->data.stream_info.max_blocksize);
+			PPR; printf("  minimum framesize: %u bytes\n", block->data.stream_info.min_framesize);
+			PPR; printf("  maximum framesize: %u bytes\n", block->data.stream_info.max_framesize);
+			PPR; printf("  sample_rate: %u Hz\n", block->data.stream_info.sample_rate);
+			PPR; printf("  channels: %u\n", block->data.stream_info.channels);
+			PPR; printf("  bits-per-sample: %u\n", block->data.stream_info.bits_per_sample);
+			PPR; printf("  total samples: %" PRIu64 "\n", block->data.stream_info.total_samples);
+			PPR; printf("  MD5 signature: ");
+			for(i = 0; i < 16; i++) {
+				printf("%02x", (unsigned)block->data.stream_info.md5sum[i]);
+			}
+			printf("\n");
+			break;
+		case FLAC__METADATA_TYPE_PADDING:
+			/* nothing to print */
+			break;
+		case FLAC__METADATA_TYPE_APPLICATION:
+			PPR; printf("  application ID: ");
+			for(i = 0; i < 4; i++)
+				printf("%02x", block->data.application.id[i]);
+			printf("\n");
+			PPR; printf("  data contents:\n");
+			if(0 != block->data.application.data) {
+				if(hexdump_application)
+					hexdump(filename, block->data.application.data, block->length - FLAC__STREAM_METADATA_HEADER_LENGTH, "    ");
+				else
+					(void) local_fwrite(block->data.application.data, 1, block->length - FLAC__STREAM_METADATA_HEADER_LENGTH, stdout);
+			}
+			break;
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			PPR; printf("  seek points: %u\n", block->data.seek_table.num_points);
+			for(i = 0; i < block->data.seek_table.num_points; i++) {
+				if(block->data.seek_table.points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
+					PPR; printf("    point %u: sample_number=%" PRIu64 ", stream_offset=%" PRIu64 ", frame_samples=%u\n", i, block->data.seek_table.points[i].sample_number, block->data.seek_table.points[i].stream_offset, block->data.seek_table.points[i].frame_samples);
+				}
+				else {
+					PPR; printf("    point %u: PLACEHOLDER\n", i);
+				}
+			}
+			break;
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			PPR; printf("  vendor string: ");
+			write_vc_field(0, &block->data.vorbis_comment.vendor_string, raw, stdout);
+			PPR; printf("  comments: %u\n", block->data.vorbis_comment.num_comments);
+			for(i = 0; i < block->data.vorbis_comment.num_comments; i++) {
+				PPR; printf("    comment[%u]: ", i);
+				write_vc_field(0, &block->data.vorbis_comment.comments[i], raw, stdout);
+			}
+			break;
+		case FLAC__METADATA_TYPE_CUESHEET:
+			PPR; printf("  media catalog number: %s\n", block->data.cue_sheet.media_catalog_number);
+			PPR; printf("  lead-in: %" PRIu64 "\n", block->data.cue_sheet.lead_in);
+			PPR; printf("  is CD: %s\n", block->data.cue_sheet.is_cd? "true":"false");
+			PPR; printf("  number of tracks: %u\n", block->data.cue_sheet.num_tracks);
+			for(i = 0; i < block->data.cue_sheet.num_tracks; i++) {
+				const FLAC__StreamMetadata_CueSheet_Track *track = block->data.cue_sheet.tracks+i;
+				const FLAC__bool is_last = (i == block->data.cue_sheet.num_tracks-1);
+				const FLAC__bool is_leadout = is_last && track->num_indices == 0;
+				PPR; printf("    track[%u]\n", i);
+				PPR; printf("      offset: %" PRIu64 "\n", track->offset);
+				if(is_last) {
+					PPR; printf("      number: %u (%s)\n", (unsigned)track->number, is_leadout? "LEAD-OUT" : "INVALID");
+				}
+				else {
+					PPR; printf("      number: %u\n", (unsigned)track->number);
+				}
+				if(!is_leadout) {
+					PPR; printf("      ISRC: %s\n", track->isrc);
+					PPR; printf("      type: %s\n", track->type == 1? "DATA" : "AUDIO");
+					PPR; printf("      pre-emphasis: %s\n", track->pre_emphasis? "true":"false");
+					PPR; printf("      number of index points: %u\n", track->num_indices);
+					for(j = 0; j < track->num_indices; j++) {
+						const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices+j;
+						PPR; printf("        index[%u]\n", j);
+						PPR; printf("          offset: %" PRIu64 "\n", indx->offset);
+						PPR; printf("          number: %u\n", (unsigned)indx->number);
+					}
+				}
+			}
+			break;
+		case FLAC__METADATA_TYPE_PICTURE:
+			PPR; printf("  type: %u (%s)\n", block->data.picture.type, block->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED? FLAC__StreamMetadata_Picture_TypeString[block->data.picture.type] : "UNDEFINED");
+			PPR; printf("  MIME type: %s\n", block->data.picture.mime_type);
+			PPR; printf("  description: %s\n", block->data.picture.description);
+			PPR; printf("  width: %u\n", (unsigned)block->data.picture.width);
+			PPR; printf("  height: %u\n", (unsigned)block->data.picture.height);
+			PPR; printf("  depth: %u\n", (unsigned)block->data.picture.depth);
+			PPR; printf("  colors: %u%s\n", (unsigned)block->data.picture.colors, block->data.picture.colors? "" : " (unindexed)");
+			PPR; printf("  data length: %u\n", (unsigned)block->data.picture.data_length);
+			PPR; printf("  data:\n");
+			if(0 != block->data.picture.data)
+				hexdump(filename, block->data.picture.data, block->data.picture.data_length, "    ");
+			break;
+		default:
+			PPR; printf("  data contents:\n");
+			if(0 != block->data.unknown.data)
+				hexdump(filename, block->data.unknown.data, block->length, "    ");
+			break;
+	}
+#undef PPR
+}
diff --git a/src/metaflac/operations.h b/src/metaflac/operations.h
new file mode 100644
index 0000000..1c630aa
--- /dev/null
+++ b/src/metaflac/operations.h
@@ -0,0 +1,27 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef metaflac__operations_h
+#define metaflac__operations_h
+
+#include "options.h"
+
+FLAC__bool do_operations(const CommandLineOptions *options);
+
+#endif
diff --git a/src/metaflac/operations_shorthand.h b/src/metaflac/operations_shorthand.h
new file mode 100644
index 0000000..a262d4f
--- /dev/null
+++ b/src/metaflac/operations_shorthand.h
@@ -0,0 +1,26 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "options.h"
+
+FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write);
+FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw);
diff --git a/src/metaflac/operations_shorthand_cuesheet.c b/src/metaflac/operations_shorthand_cuesheet.c
new file mode 100644
index 0000000..fa7cb8e
--- /dev/null
+++ b/src/metaflac/operations_shorthand_cuesheet.c
@@ -0,0 +1,214 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "operations_shorthand.h"
+
+static FLAC__bool import_cs_from(const char *filename, FLAC__StreamMetadata **cuesheet, const char *cs_filename, FLAC__bool *needs_write, FLAC__uint64 lead_out_offset, unsigned sample_rate, FLAC__bool is_cdda, Argument_AddSeekpoint *add_seekpoint_link);
+static FLAC__bool export_cs_to(const char *filename, const FLAC__StreamMetadata *cuesheet, const char *cs_filename);
+
+FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write)
+{
+	FLAC__bool ok = true;
+	FLAC__StreamMetadata *cuesheet = 0;
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+	FLAC__uint64 lead_out_offset = 0;
+	FLAC__bool is_cdda = false;
+	unsigned sample_rate = 0;
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	do {
+		FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
+		if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+			lead_out_offset = block->data.stream_info.total_samples;
+			if(lead_out_offset == 0) {
+				flac_fprintf(stderr, "%s: ERROR: FLAC file must have total_samples set in STREAMINFO in order to import/export cuesheet\n", filename);
+				FLAC__metadata_iterator_delete(iterator);
+				return false;
+			}
+			sample_rate = block->data.stream_info.sample_rate;
+			is_cdda = (block->data.stream_info.channels == 1 || block->data.stream_info.channels == 2) && (block->data.stream_info.bits_per_sample == 16) && (sample_rate == 44100);
+		}
+		else if(block->type == FLAC__METADATA_TYPE_CUESHEET)
+			cuesheet = block;
+	} while(FLAC__metadata_iterator_next(iterator));
+
+	if(lead_out_offset == 0) {
+		flac_fprintf(stderr, "%s: ERROR: FLAC stream has no STREAMINFO block\n", filename);
+		FLAC__metadata_iterator_delete(iterator);
+		return false;
+	}
+
+	switch(operation->type) {
+		case OP__IMPORT_CUESHEET_FROM:
+			if(0 != cuesheet) {
+				flac_fprintf(stderr, "%s: ERROR: FLAC file already has CUESHEET block\n", filename);
+				ok = false;
+			}
+			else {
+				ok = import_cs_from(filename, &cuesheet, operation->argument.import_cuesheet_from.filename, needs_write, lead_out_offset, sample_rate, is_cdda, operation->argument.import_cuesheet_from.add_seekpoint_link);
+				if(ok) {
+					/* append CUESHEET block */
+					while(FLAC__metadata_iterator_next(iterator))
+						;
+					if(!FLAC__metadata_iterator_insert_block_after(iterator, cuesheet)) {
+						print_error_with_chain_status(chain, "%s: ERROR: adding new CUESHEET block to metadata", filename);
+						FLAC__metadata_object_delete(cuesheet);
+						ok = false;
+					}
+				}
+			}
+			break;
+		case OP__EXPORT_CUESHEET_TO:
+			if(0 == cuesheet) {
+				flac_fprintf(stderr, "%s: ERROR: FLAC file has no CUESHEET block\n", filename);
+				ok = false;
+			}
+			else
+				ok = export_cs_to(filename, cuesheet, operation->argument.filename.value);
+			break;
+		default:
+			ok = false;
+			FLAC__ASSERT(0);
+			break;
+	};
+
+	FLAC__metadata_iterator_delete(iterator);
+	return ok;
+}
+
+/*
+ * local routines
+ */
+
+FLAC__bool import_cs_from(const char *filename, FLAC__StreamMetadata **cuesheet, const char *cs_filename, FLAC__bool *needs_write, FLAC__uint64 lead_out_offset, unsigned sample_rate, FLAC__bool is_cdda, Argument_AddSeekpoint *add_seekpoint_link)
+{
+	FILE *f;
+	const char *error_message;
+	char **seekpoint_specification = add_seekpoint_link? &(add_seekpoint_link->specification) : 0;
+	unsigned last_line_read;
+
+	if(0 == cs_filename || strlen(cs_filename) == 0) {
+		flac_fprintf(stderr, "%s: ERROR: empty import file name\n", filename);
+		return false;
+	}
+	if(0 == strcmp(cs_filename, "-"))
+		f = stdin;
+	else
+		f = flac_fopen(cs_filename, "r");
+
+	if(0 == f) {
+		flac_fprintf(stderr, "%s: ERROR: can't open import file %s: %s\n", filename, cs_filename, strerror(errno));
+		return false;
+	}
+
+	*cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset);
+
+	if(f != stdin)
+		fclose(f);
+
+	if(0 == *cuesheet) {
+		flac_fprintf(stderr, "%s: ERROR: while parsing cuesheet \"%s\" on line %u: %s\n", filename, cs_filename, last_line_read, error_message);
+		return false;
+	}
+
+	if(!FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/false, &error_message)) {
+		flac_fprintf(stderr, "%s: ERROR parsing cuesheet \"%s\": %s\n", filename, cs_filename, error_message);
+		return false;
+	}
+
+	/* if we're expecting CDDA, warn about non-compliance */
+	if(is_cdda && !FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/true, &error_message)) {
+		flac_fprintf(stderr, "%s: WARNING cuesheet \"%s\" is not audio CD compliant: %s\n", filename, cs_filename, error_message);
+		(*cuesheet)->data.cue_sheet.is_cd = false;
+	}
+
+	/* add seekpoints for each index point if required */
+	if(0 != seekpoint_specification) {
+		char spec[128];
+		unsigned track, indx;
+		const FLAC__StreamMetadata_CueSheet *cs = &(*cuesheet)->data.cue_sheet;
+		if(0 == *seekpoint_specification)
+			*seekpoint_specification = local_strdup("");
+		for(track = 0; track < cs->num_tracks; track++) {
+			const FLAC__StreamMetadata_CueSheet_Track *tr = cs->tracks+track;
+			for(indx = 0; indx < tr->num_indices; indx++) {
+				flac_snprintf(spec, sizeof (spec), "%" PRIu64 ";", (tr->offset + tr->indices[indx].offset));
+				local_strcat(seekpoint_specification, spec);
+			}
+		}
+	}
+
+	*needs_write = true;
+	return true;
+}
+
+FLAC__bool export_cs_to(const char *filename, const FLAC__StreamMetadata *cuesheet, const char *cs_filename)
+{
+	FILE *f;
+	char *ref = 0;
+	size_t reflen;
+
+	if(0 == cs_filename || strlen(cs_filename) == 0) {
+		flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
+		return false;
+	}
+	if(0 == strcmp(cs_filename, "-"))
+		f = stdout;
+	else
+		f = flac_fopen(cs_filename, "w");
+
+	if(0 == f) {
+		flac_fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, cs_filename, strerror(errno));
+		return false;
+	}
+
+	reflen = strlen(filename) + 7 + 1;
+	if(0 == (ref = malloc(reflen))) {
+		flac_fprintf(stderr, "%s: ERROR: allocating memory\n", filename);
+		if(f != stdout)
+			fclose(f);
+		return false;
+	}
+
+	flac_snprintf(ref, reflen, "\"%s\" FLAC", filename);
+
+	grabbag__cuesheet_emit(f, cuesheet, ref);
+
+	free(ref);
+
+	if(f != stdout)
+		fclose(f);
+
+	return true;
+}
diff --git a/src/metaflac/operations_shorthand_picture.c b/src/metaflac/operations_shorthand_picture.c
new file mode 100644
index 0000000..7afa412
--- /dev/null
+++ b/src/metaflac/operations_shorthand_picture.c
@@ -0,0 +1,176 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/grabbag.h" /* for grabbag__picture_parse_specification() etc */
+
+#include "operations_shorthand.h"
+
+static FLAC__bool import_pic_from(const char *filename, FLAC__StreamMetadata **picture, const char *specification, FLAC__bool *needs_write);
+static FLAC__bool export_pic_to(const char *filename, const FLAC__StreamMetadata *picture, const char *pic_filename);
+
+FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write)
+{
+	FLAC__bool ok = true, has_type1 = false, has_type2 = false;
+	FLAC__StreamMetadata *picture = 0;
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	switch(operation->type) {
+		case OP__IMPORT_PICTURE_FROM:
+			ok = import_pic_from(filename, &picture, operation->argument.specification.value, needs_write);
+			if(ok) {
+				/* append PICTURE block */
+				while(FLAC__metadata_iterator_next(iterator))
+					;
+				if(!FLAC__metadata_iterator_insert_block_after(iterator, picture)) {
+					print_error_with_chain_status(chain, "%s: ERROR: adding new PICTURE block to metadata", filename);
+					FLAC__metadata_object_delete(picture);
+					ok = false;
+				}
+			}
+			if(ok) {
+				/* check global PICTURE constraints (max 1 block each of type=1 and type=2) */
+				while(FLAC__metadata_iterator_prev(iterator))
+					;
+				do {
+					FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
+					if(block->type == FLAC__METADATA_TYPE_PICTURE) {
+						if(block->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
+							if(has_type1) {
+								print_error_with_chain_status(chain, "%s: ERROR: FLAC stream can only have one 32x32 standard icon (type=1) PICTURE block", filename);
+								ok = false;
+							}
+							has_type1 = true;
+						}
+						else if(block->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
+							if(has_type2) {
+								print_error_with_chain_status(chain, "%s: ERROR: FLAC stream can only have one icon (type=2) PICTURE block", filename);
+								ok = false;
+							}
+							has_type2 = true;
+						}
+					}
+				} while(FLAC__metadata_iterator_next(iterator));
+			}
+			break;
+		case OP__EXPORT_PICTURE_TO:
+			{
+				const Argument_BlockNumber *a = operation->argument.export_picture_to.block_number_link;
+				int block_number = (a && a->num_entries > 0)? (int)a->entries[0] : -1;
+				unsigned i = 0;
+				do {
+					FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
+					if(block->type == FLAC__METADATA_TYPE_PICTURE && (block_number < 0 || i == (unsigned)block_number))
+						picture = block;
+					i++;
+				} while(FLAC__metadata_iterator_next(iterator) && 0 == picture);
+				if(0 == picture) {
+					if(block_number < 0)
+						flac_fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block\n", filename);
+					else
+						flac_fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block at block #%d\n", filename, block_number);
+					ok = false;
+				}
+				else
+					ok = export_pic_to(filename, picture, operation->argument.filename.value);
+			}
+			break;
+		default:
+			ok = false;
+			FLAC__ASSERT(0);
+			break;
+	};
+
+	FLAC__metadata_iterator_delete(iterator);
+	return ok;
+}
+
+/*
+ * local routines
+ */
+
+FLAC__bool import_pic_from(const char *filename, FLAC__StreamMetadata **picture, const char *specification, FLAC__bool *needs_write)
+{
+	const char *error_message;
+
+	if(0 == specification || strlen(specification) == 0) {
+		flac_fprintf(stderr, "%s: ERROR: empty picture specification\n", filename);
+		return false;
+	}
+
+	*picture = grabbag__picture_parse_specification(specification, &error_message);
+
+	if(0 == *picture) {
+		flac_fprintf(stderr, "%s: ERROR: while parsing picture specification \"%s\": %s\n", filename, specification, error_message);
+		return false;
+	}
+
+	if(!FLAC__format_picture_is_legal(&(*picture)->data.picture, &error_message)) {
+		flac_fprintf(stderr, "%s: ERROR: new PICTURE block for \"%s\" is illegal: %s\n", filename, specification, error_message);
+		return false;
+	}
+
+	*needs_write = true;
+	return true;
+}
+
+FLAC__bool export_pic_to(const char *filename, const FLAC__StreamMetadata *picture, const char *pic_filename)
+{
+	FILE *f;
+	const FLAC__uint32 len = picture->data.picture.data_length;
+
+	if(0 == pic_filename || strlen(pic_filename) == 0) {
+		flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
+		return false;
+	}
+	if(0 == strcmp(pic_filename, "-"))
+		f = grabbag__file_get_binary_stdout();
+	else
+		f = flac_fopen(pic_filename, "wb");
+
+	if(0 == f) {
+		flac_fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, pic_filename, strerror(errno));
+		return false;
+	}
+
+	if(fwrite(picture->data.picture.data, 1, len, f) != len) {
+		flac_fprintf(stderr, "%s: ERROR: writing PICTURE data to file\n", filename);
+		if(f != stdout)
+			fclose(f);
+		return false;
+	}
+
+	if(f != stdout)
+		fclose(f);
+
+	return true;
+}
diff --git a/src/metaflac/operations_shorthand_seektable.c b/src/metaflac/operations_shorthand_seektable.c
new file mode 100644
index 0000000..99e97ad
--- /dev/null
+++ b/src/metaflac/operations_shorthand_seektable.c
@@ -0,0 +1,218 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+#include "operations_shorthand.h"
+
+static FLAC__bool populate_seekpoint_values(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write);
+
+FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write)
+{
+	FLAC__bool ok = true, found_seektable_block = false;
+	FLAC__StreamMetadata *block = 0;
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+	FLAC__uint64 total_samples = 0;
+	unsigned sample_rate = 0;
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	do {
+		block = FLAC__metadata_iterator_get_block(iterator);
+		if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+			sample_rate = block->data.stream_info.sample_rate;
+			total_samples = block->data.stream_info.total_samples;
+		}
+		else if(block->type == FLAC__METADATA_TYPE_SEEKTABLE)
+			found_seektable_block = true;
+	} while(!found_seektable_block && FLAC__metadata_iterator_next(iterator));
+
+	if(total_samples == 0) {
+		flac_fprintf(stderr, "%s: ERROR: cannot add seekpoints because STREAMINFO block does not specify total_samples\n", filename);
+		return false;
+	}
+
+	if(!found_seektable_block) {
+		/* create a new block */
+		block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+		if(0 == block)
+			die("out of memory allocating SEEKTABLE block");
+		while(FLAC__metadata_iterator_prev(iterator))
+			;
+		if(!FLAC__metadata_iterator_insert_block_after(iterator, block)) {
+			print_error_with_chain_status(chain, "%s: ERROR: adding new SEEKTABLE block to metadata", filename);
+			FLAC__metadata_object_delete(block);
+			return false;
+		}
+		/* iterator is left pointing to new block */
+		FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == block);
+	}
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	if(!grabbag__seektable_convert_specification_to_template(specification, /*only_explicit_placeholders=*/false, total_samples, sample_rate, block, /*spec_has_real_points=*/0)) {
+		flac_fprintf(stderr, "%s: ERROR (internal) preparing seektable with seekpoints\n", filename);
+		return false;
+	}
+
+	ok = populate_seekpoint_values(filename, block, needs_write);
+
+	if(ok)
+		(void) FLAC__format_seektable_sort(&block->data.seek_table);
+
+	return ok;
+}
+
+/*
+ * local routines
+ */
+
+typedef struct {
+	FLAC__StreamMetadata_SeekTable *seektable_template;
+	FLAC__uint64 samples_written;
+	FLAC__uint64 audio_offset, last_offset;
+	unsigned first_seekpoint_to_check;
+	FLAC__bool error_occurred;
+	FLAC__StreamDecoderErrorStatus error_status;
+} ClientData;
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	ClientData *cd = (ClientData*)client_data;
+
+	(void)buffer;
+	FLAC__ASSERT(0 != cd);
+
+	if(!cd->error_occurred) {
+		const unsigned blocksize = frame->header.blocksize;
+		const FLAC__uint64 frame_first_sample = cd->samples_written;
+		const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
+		FLAC__uint64 test_sample;
+		unsigned i;
+		for(i = cd->first_seekpoint_to_check; i < cd->seektable_template->num_points; i++) {
+			test_sample = cd->seektable_template->points[i].sample_number;
+			if(test_sample > frame_last_sample) {
+				break;
+			}
+			else if(test_sample >= frame_first_sample) {
+				cd->seektable_template->points[i].sample_number = frame_first_sample;
+				cd->seektable_template->points[i].stream_offset = cd->last_offset - cd->audio_offset;
+				cd->seektable_template->points[i].frame_samples = blocksize;
+				cd->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 {
+				cd->first_seekpoint_to_check++;
+			}
+		}
+		cd->samples_written += blocksize;
+		if(!FLAC__stream_decoder_get_decode_position(decoder, &cd->last_offset))
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+	}
+	else
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	ClientData *cd = (ClientData*)client_data;
+
+	(void)decoder;
+	FLAC__ASSERT(0 != cd);
+
+	if(!cd->error_occurred) { /* don't let multiple errors overwrite the first one */
+		cd->error_occurred = true;
+		cd->error_status = status;
+	}
+}
+
+FLAC__bool populate_seekpoint_values(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write)
+{
+	FLAC__StreamDecoder *decoder;
+	ClientData client_data;
+	FLAC__bool ok = true;
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	client_data.seektable_template = &block->data.seek_table;
+	client_data.samples_written = 0;
+	/* client_data.audio_offset must be determined later */
+	client_data.first_seekpoint_to_check = 0;
+	client_data.error_occurred = false;
+
+	decoder = FLAC__stream_decoder_new();
+
+	if(0 == decoder) {
+		flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) creating the decoder instance\n", filename);
+		return false;
+	}
+
+	FLAC__stream_decoder_set_md5_checking(decoder, false);
+	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+
+	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, /*metadata_callback=*/0, error_callback_, &client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) initializing the decoder instance (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+		ok = false;
+	}
+
+	if(ok && !FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
+		flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+		ok = false;
+	}
+
+	if(ok && !FLAC__stream_decoder_get_decode_position(decoder, &client_data.audio_offset)) {
+		flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file\n", filename);
+		ok = false;
+	}
+	client_data.last_offset = client_data.audio_offset;
+
+	if(ok && !FLAC__stream_decoder_process_until_end_of_stream(decoder)) {
+		flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+		ok = false;
+	}
+
+	if(ok && client_data.error_occurred) {
+		flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%u:%s)\n", filename, (unsigned)client_data.error_status, FLAC__StreamDecoderErrorStatusString[client_data.error_status]);
+		ok = false;
+	}
+
+	*needs_write = true;
+	FLAC__stream_decoder_delete(decoder);
+	return ok;
+}
diff --git a/src/metaflac/operations_shorthand_streaminfo.c b/src/metaflac/operations_shorthand_streaminfo.c
new file mode 100644
index 0000000..60ac793
--- /dev/null
+++ b/src/metaflac/operations_shorthand_streaminfo.c
@@ -0,0 +1,127 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/compat.h"
+#include <string.h>
+#include "operations_shorthand.h"
+
+FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write)
+{
+	unsigned i;
+	FLAC__bool ok = true;
+	FLAC__StreamMetadata *block;
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	block = FLAC__metadata_iterator_get_block(iterator);
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+	if(prefix_with_filename)
+		flac_printf("%s:", filename);
+
+	switch(operation->type) {
+		case OP__SHOW_MD5SUM:
+			for(i = 0; i < 16; i++)
+				printf("%02x", block->data.stream_info.md5sum[i]);
+			printf("\n");
+			break;
+		case OP__SHOW_MIN_BLOCKSIZE:
+			printf("%u\n", block->data.stream_info.min_blocksize);
+			break;
+		case OP__SHOW_MAX_BLOCKSIZE:
+			printf("%u\n", block->data.stream_info.max_blocksize);
+			break;
+		case OP__SHOW_MIN_FRAMESIZE:
+			printf("%u\n", block->data.stream_info.min_framesize);
+			break;
+		case OP__SHOW_MAX_FRAMESIZE:
+			printf("%u\n", block->data.stream_info.max_framesize);
+			break;
+		case OP__SHOW_SAMPLE_RATE:
+			printf("%u\n", block->data.stream_info.sample_rate);
+			break;
+		case OP__SHOW_CHANNELS:
+			printf("%u\n", block->data.stream_info.channels);
+			break;
+		case OP__SHOW_BPS:
+			printf("%u\n", block->data.stream_info.bits_per_sample);
+			break;
+		case OP__SHOW_TOTAL_SAMPLES:
+			printf("%" PRIu64 "\n", block->data.stream_info.total_samples);
+			break;
+		case OP__SET_MD5SUM:
+			memcpy(block->data.stream_info.md5sum, operation->argument.streaminfo_md5.value, 16);
+			*needs_write = true;
+			break;
+		case OP__SET_MIN_BLOCKSIZE:
+			block->data.stream_info.min_blocksize = operation->argument.streaminfo_uint32.value;
+			*needs_write = true;
+			break;
+		case OP__SET_MAX_BLOCKSIZE:
+			block->data.stream_info.max_blocksize = operation->argument.streaminfo_uint32.value;
+			*needs_write = true;
+			break;
+		case OP__SET_MIN_FRAMESIZE:
+			block->data.stream_info.min_framesize = operation->argument.streaminfo_uint32.value;
+			*needs_write = true;
+			break;
+		case OP__SET_MAX_FRAMESIZE:
+			block->data.stream_info.max_framesize = operation->argument.streaminfo_uint32.value;
+			*needs_write = true;
+			break;
+		case OP__SET_SAMPLE_RATE:
+			block->data.stream_info.sample_rate = operation->argument.streaminfo_uint32.value;
+			*needs_write = true;
+			break;
+		case OP__SET_CHANNELS:
+			block->data.stream_info.channels = operation->argument.streaminfo_uint32.value;
+			*needs_write = true;
+			break;
+		case OP__SET_BPS:
+			block->data.stream_info.bits_per_sample = operation->argument.streaminfo_uint32.value;
+			*needs_write = true;
+			break;
+		case OP__SET_TOTAL_SAMPLES:
+			block->data.stream_info.total_samples = operation->argument.streaminfo_uint64.value;
+			*needs_write = true;
+			break;
+		default:
+			ok = false;
+			FLAC__ASSERT(0);
+			break;
+	};
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	return ok;
+}
diff --git a/src/metaflac/operations_shorthand_vorbiscomment.c b/src/metaflac/operations_shorthand_vorbiscomment.c
new file mode 100644
index 0000000..3eae3b4
--- /dev/null
+++ b/src/metaflac/operations_shorthand_vorbiscomment.c
@@ -0,0 +1,374 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/grabbag.h" /* for grabbag__file_get_filesize() */
+#include "share/utf8.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "operations_shorthand.h"
+#include "share/compat.h"
+
+static FLAC__bool remove_vc_all(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write);
+static FLAC__bool remove_vc_field(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write);
+static FLAC__bool remove_vc_firstfield(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write);
+static FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw);
+static FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool *needs_write, FLAC__bool raw);
+static FLAC__bool export_vc_to(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool raw);
+
+FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw)
+{
+	FLAC__bool ok = true, found_vc_block = false;
+	FLAC__StreamMetadata *block = 0;
+	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+
+	if(0 == iterator)
+		die("out of memory allocating iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	do {
+		block = FLAC__metadata_iterator_get_block(iterator);
+		if(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+			found_vc_block = true;
+	} while(!found_vc_block && FLAC__metadata_iterator_next(iterator));
+
+	if(!found_vc_block) {
+		/* create a new block if necessary */
+		if(operation->type == OP__SET_VC_FIELD || operation->type == OP__IMPORT_VC_FROM) {
+			block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+			if(0 == block)
+				die("out of memory allocating VORBIS_COMMENT block");
+			while(FLAC__metadata_iterator_next(iterator))
+				;
+			if(!FLAC__metadata_iterator_insert_block_after(iterator, block)) {
+				print_error_with_chain_status(chain, "%s: ERROR: adding new VORBIS_COMMENT block to metadata", filename);
+				return false;
+			}
+			/* iterator is left pointing to new block */
+			FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == block);
+		}
+		else {
+			FLAC__metadata_iterator_delete(iterator);
+			return ok;
+		}
+	}
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	switch(operation->type) {
+		case OP__SHOW_VC_VENDOR:
+			write_vc_field(prefix_with_filename? filename : 0, &block->data.vorbis_comment.vendor_string, raw, stdout);
+			break;
+		case OP__SHOW_VC_FIELD:
+			write_vc_fields(prefix_with_filename? filename : 0, operation->argument.vc_field_name.value, block->data.vorbis_comment.comments, block->data.vorbis_comment.num_comments, raw, stdout);
+			break;
+		case OP__REMOVE_VC_ALL:
+			ok = remove_vc_all(filename, block, needs_write);
+			break;
+		case OP__REMOVE_VC_FIELD:
+			ok = remove_vc_field(filename, block, operation->argument.vc_field_name.value, needs_write);
+			break;
+		case OP__REMOVE_VC_FIRSTFIELD:
+			ok = remove_vc_firstfield(filename, block, operation->argument.vc_field_name.value, needs_write);
+			break;
+		case OP__SET_VC_FIELD:
+#ifdef _WIN32 /* do not convert anything or things will break */
+			ok = set_vc_field(filename, block, &operation->argument.vc_field, needs_write, true);
+#else
+			ok = set_vc_field(filename, block, &operation->argument.vc_field, needs_write, raw);
+#endif
+			break;
+		case OP__IMPORT_VC_FROM:
+			ok = import_vc_from(filename, block, &operation->argument.filename, needs_write, raw);
+			break;
+		case OP__EXPORT_VC_TO:
+			ok = export_vc_to(filename, block, &operation->argument.filename, raw);
+			break;
+		default:
+			ok = false;
+			FLAC__ASSERT(0);
+			break;
+	};
+
+	FLAC__metadata_iterator_delete(iterator);
+	return ok;
+}
+
+/*
+ * local routines
+ */
+
+FLAC__bool remove_vc_all(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write)
+{
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(0 != needs_write);
+
+	if(0 != block->data.vorbis_comment.comments) {
+		FLAC__ASSERT(block->data.vorbis_comment.num_comments > 0);
+		if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, 0)) {
+			flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+			return false;
+		}
+		*needs_write = true;
+	}
+	else {
+		FLAC__ASSERT(block->data.vorbis_comment.num_comments == 0);
+	}
+
+	return true;
+}
+
+FLAC__bool remove_vc_field(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write)
+{
+	int n;
+
+	FLAC__ASSERT(0 != needs_write);
+
+	n = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, field_name);
+
+	if(n < 0) {
+		flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+		return false;
+	}
+	else if(n > 0)
+		*needs_write = true;
+
+	return true;
+}
+
+FLAC__bool remove_vc_firstfield(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write)
+{
+	int n;
+
+	FLAC__ASSERT(0 != needs_write);
+
+	n = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, field_name);
+
+	if(n < 0) {
+		flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+		return false;
+	}
+	else if(n > 0)
+		*needs_write = true;
+
+	return true;
+}
+
+FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw)
+{
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+	char *converted;
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(0 != field);
+	FLAC__ASSERT(0 != needs_write);
+
+	if(field->field_value_from_file) {
+		/* read the file into 'data' */
+		FILE *f = 0;
+		char *data = 0;
+		const FLAC__off_t size = grabbag__file_get_filesize(field->field_value);
+		if(size < 0) {
+			flac_fprintf(stderr, "%s: ERROR: can't open file '%s' for '%s' tag value\n", filename, field->field_value, field->field_name);
+			return false;
+		}
+		if(size >= 0x100000) { /* magic arbitrary limit, actual format limit is near 16MB */
+			flac_fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value is too large\n", filename, field->field_value, field->field_name);
+			return false;
+		}
+		if(0 == (data = malloc(size+1)))
+			die("out of memory allocating tag value");
+		data[size] = '\0';
+		if(0 == (f = flac_fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) {
+			flac_fprintf(stderr, "%s: ERROR: while reading file '%s' for '%s' tag value: %s\n", filename, field->field_value, field->field_name, strerror(errno));
+			free(data);
+			if(f)
+				fclose(f);
+			return false;
+		}
+		fclose(f);
+		if(strlen(data) != (size_t)size) {
+			free(data);
+			flac_fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value has embedded NULs\n", filename, field->field_value, field->field_name);
+			return false;
+		}
+
+		/* move 'data' into 'converted', converting to UTF-8 if necessary */
+		if(raw) {
+			converted = data;
+		}
+		else if(utf8_encode(data, &converted) >= 0) {
+			free(data);
+		}
+		else {
+			free(data);
+			flac_fprintf(stderr, "%s: ERROR: converting file '%s' contents to UTF-8 for tag value\n", filename, field->field_value);
+			return false;
+		}
+
+		/* create and entry and append it */
+		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) {
+			free(converted);
+			flac_fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value is not valid UTF-8\n", filename, field->field_value, field->field_name);
+			return false;
+		}
+		free(converted);
+		if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+			flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+			return false;
+		}
+
+		*needs_write = true;
+		return true;
+	}
+	else {
+		FLAC__bool needs_free = false;
+		entry.entry = (FLAC__byte *)field->field;
+		if(raw) {
+			entry.entry = (FLAC__byte *)field->field;
+		}
+		else if(utf8_encode(field->field, &converted) >= 0) {
+			entry.entry = (FLAC__byte *)converted;
+			needs_free = true;
+		}
+		else {
+			flac_fprintf(stderr, "%s: ERROR: converting comment '%s' to UTF-8\n", filename, field->field);
+			return false;
+		}
+		entry.length = strlen((const char *)entry.entry);
+		if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) {
+			if(needs_free)
+				free(converted);
+			/*
+			 * our previous parsing has already established that the field
+			 * name is OK, so it must be the field value
+			 */
+			flac_fprintf(stderr, "%s: ERROR: tag value for '%s' is not valid UTF-8\n", filename, field->field_name);
+			return false;
+		}
+
+		if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+			if(needs_free)
+				free(converted);
+			flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+			return false;
+		}
+
+		*needs_write = true;
+		if(needs_free)
+			free(converted);
+		return true;
+	}
+}
+
+FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool *needs_write, FLAC__bool raw)
+{
+	FILE *f;
+	char line[65536];
+	FLAC__bool ret;
+
+	if(0 == vc_filename->value || strlen(vc_filename->value) == 0) {
+		flac_fprintf(stderr, "%s: ERROR: empty import file name\n", filename);
+		return false;
+	}
+	if(0 == strcmp(vc_filename->value, "-"))
+		f = stdin;
+	else
+		f = flac_fopen(vc_filename->value, "r");
+
+	if(0 == f) {
+		flac_fprintf(stderr, "%s: ERROR: can't open import file %s: %s\n", filename, vc_filename->value, strerror(errno));
+		return false;
+	}
+
+	ret = true;
+	while(ret && !feof(f) && fgets(line, sizeof(line), f) != NULL) {
+		if(!feof(f)) {
+			char *p = strchr(line, '\n');
+			if(0 == p) {
+				flac_fprintf(stderr, "%s: ERROR: line too long, aborting\n", vc_filename->value);
+				ret = false;
+			}
+			else {
+				const char *violation;
+				Argument_VcField field;
+				*p = '\0';
+				memset(&field, 0, sizeof(Argument_VcField));
+				field.field_value_from_file = false;
+				if(!parse_vorbis_comment_field(line, &field.field, &field.field_name, &field.field_value, &field.field_value_length, &violation)) {
+					FLAC__ASSERT(0 != violation);
+					flac_fprintf(stderr, "%s: ERROR: malformed vorbis comment field \"%s\",\n       %s\n", vc_filename->value, line, violation);
+					ret = false;
+				}
+				else {
+					ret = set_vc_field(filename, block, &field, needs_write, raw);
+				}
+				if(0 != field.field)
+					free(field.field);
+				if(0 != field.field_name)
+					free(field.field_name);
+				if(0 != field.field_value)
+					free(field.field_value);
+			}
+		}
+	};
+
+	if(f != stdin)
+		fclose(f);
+	return ret;
+}
+
+FLAC__bool export_vc_to(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool raw)
+{
+	FILE *f;
+	FLAC__bool ret;
+
+	if(0 == vc_filename->value || strlen(vc_filename->value) == 0) {
+		flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
+		return false;
+	}
+	if(0 == strcmp(vc_filename->value, "-"))
+		f = stdout;
+	else
+		f = flac_fopen(vc_filename->value, "w");
+
+	if(0 == f) {
+		flac_fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, vc_filename->value, strerror(errno));
+		return false;
+	}
+
+	ret = true;
+
+	write_vc_fields(0, 0, block->data.vorbis_comment.comments, block->data.vorbis_comment.num_comments, raw, f);
+
+	if(f != stdout)
+		fclose(f);
+	return ret;
+}
diff --git a/src/metaflac/options.c b/src/metaflac/options.c
new file mode 100644
index 0000000..d91084f
--- /dev/null
+++ b/src/metaflac/options.c
@@ -0,0 +1,1093 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "options.h"
+#include "usage.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/grabbag/replaygain.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+   share__getopt format struct; note we don't use short options so we just
+   set the 'val' field to 0 everywhere to indicate a valid option.
+*/
+struct share__option long_options_[] = {
+	/* global options */
+	{ "preserve-modtime", 0, 0, 0 },
+	{ "with-filename", 0, 0, 0 },
+	{ "no-filename", 0, 0, 0 },
+	{ "no-utf8-convert", 0, 0, 0 },
+	{ "dont-use-padding", 0, 0, 0 },
+	{ "no-cued-seekpoints", 0, 0, 0 },
+	/* shorthand operations */
+	{ "show-md5sum", 0, 0, 0 },
+	{ "show-min-blocksize", 0, 0, 0 },
+	{ "show-max-blocksize", 0, 0, 0 },
+	{ "show-min-framesize", 0, 0, 0 },
+	{ "show-max-framesize", 0, 0, 0 },
+	{ "show-sample-rate", 0, 0, 0 },
+	{ "show-channels", 0, 0, 0 },
+	{ "show-bps", 0, 0, 0 },
+	{ "show-total-samples", 0, 0, 0 },
+	{ "set-md5sum", 1, 0, 0 }, /* undocumented */
+	{ "set-min-blocksize", 1, 0, 0 }, /* undocumented */
+	{ "set-max-blocksize", 1, 0, 0 }, /* undocumented */
+	{ "set-min-framesize", 1, 0, 0 }, /* undocumented */
+	{ "set-max-framesize", 1, 0, 0 }, /* undocumented */
+	{ "set-sample-rate", 1, 0, 0 }, /* undocumented */
+	{ "set-channels", 1, 0, 0 }, /* undocumented */
+	{ "set-bps", 1, 0, 0 }, /* undocumented */
+	{ "set-total-samples", 1, 0, 0 }, /* undocumented */ /* WATCHOUT: used by test/test_flac.sh on windows */
+	{ "show-vendor-tag", 0, 0, 0 },
+	{ "show-tag", 1, 0, 0 },
+	{ "remove-all-tags", 0, 0, 0 },
+	{ "remove-tag", 1, 0, 0 },
+	{ "remove-first-tag", 1, 0, 0 },
+	{ "set-tag", 1, 0, 0 },
+	{ "set-tag-from-file", 1, 0, 0 },
+	{ "import-tags-from", 1, 0, 0 },
+	{ "export-tags-to", 1, 0, 0 },
+	{ "import-cuesheet-from", 1, 0, 0 },
+	{ "export-cuesheet-to", 1, 0, 0 },
+	{ "import-picture-from", 1, 0, 0 },
+	{ "export-picture-to", 1, 0, 0 },
+	{ "add-seekpoint", 1, 0, 0 },
+	{ "add-replay-gain", 0, 0, 0 },
+	{ "scan-replay-gain", 0, 0, 0 },
+	{ "remove-replay-gain", 0, 0, 0 },
+	{ "add-padding", 1, 0, 0 },
+	/* major operations */
+	{ "help", 0, 0, 0 },
+	{ "version", 0, 0, 0 },
+	{ "list", 0, 0, 0 },
+	{ "append", 0, 0, 0 },
+	{ "remove", 0, 0, 0 },
+	{ "remove-all", 0, 0, 0 },
+	{ "merge-padding", 0, 0, 0 },
+	{ "sort-padding", 0, 0, 0 },
+	/* major operation arguments */
+	{ "block-number", 1, 0, 0 },
+	{ "block-type", 1, 0, 0 },
+	{ "except-block-type", 1, 0, 0 },
+	{ "data-format", 1, 0, 0 },
+	{ "application-data-format", 1, 0, 0 },
+	{ "from-file", 1, 0, 0 },
+	{0, 0, 0, 0}
+};
+
+static FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options);
+static void append_new_operation(CommandLineOptions *options, Operation operation);
+static void append_new_argument(CommandLineOptions *options, Argument argument);
+static Operation *append_major_operation(CommandLineOptions *options, OperationType type);
+static Operation *append_shorthand_operation(CommandLineOptions *options, OperationType type);
+static Argument *find_argument(CommandLineOptions *options, ArgumentType type);
+static Operation *find_shorthand_operation(CommandLineOptions *options, OperationType type);
+static Argument *append_argument(CommandLineOptions *options, ArgumentType type);
+static FLAC__bool parse_md5(const char *src, FLAC__byte dest[16]);
+static FLAC__bool parse_uint32(const char *src, FLAC__uint32 *dest);
+static FLAC__bool parse_uint64(const char *src, FLAC__uint64 *dest);
+static FLAC__bool parse_string(const char *src, char **dest);
+static FLAC__bool parse_vorbis_comment_field_name(const char *field_ref, char **name, const char **violation);
+static FLAC__bool parse_add_seekpoint(const char *in, char **out, const char **violation);
+static FLAC__bool parse_add_padding(const char *in, unsigned *out);
+static FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out);
+static FLAC__bool parse_block_type(const char *in, Argument_BlockType *out);
+static FLAC__bool parse_data_format(const char *in, Argument_DataFormat *out);
+static FLAC__bool parse_application_data_format(const char *in, FLAC__bool *out);
+static void undocumented_warning(const char *opt);
+
+
+void init_options(CommandLineOptions *options)
+{
+	options->preserve_modtime = false;
+
+	/* '2' is a hack to mean "use default if not forced on command line" */
+	FLAC__ASSERT(true != 2);
+	options->prefix_with_filename = 2;
+
+	options->utf8_convert = true;
+	options->use_padding = true;
+	options->cued_seekpoints = true;
+	options->show_long_help = false;
+	options->show_version = false;
+	options->application_data_format_is_hexdump = false;
+
+	options->ops.operations = 0;
+	options->ops.num_operations = 0;
+	options->ops.capacity = 0;
+
+	options->args.arguments = 0;
+	options->args.num_arguments = 0;
+	options->args.capacity = 0;
+
+	options->args.checks.num_shorthand_ops = 0;
+	options->args.checks.num_major_ops = 0;
+	options->args.checks.has_block_type = false;
+	options->args.checks.has_except_block_type = false;
+
+	options->num_files = 0;
+	options->filenames = 0;
+}
+
+FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options)
+{
+	int ret;
+	int option_index = 1;
+	FLAC__bool had_error = false;
+
+	while ((ret = share__getopt_long(argc, argv, "", long_options_, &option_index)) != -1) {
+		switch (ret) {
+			case 0:
+				had_error |= !parse_option(option_index, share__optarg, options);
+				break;
+			case '?':
+			case ':':
+				had_error = true;
+				break;
+			default:
+				FLAC__ASSERT(0);
+				break;
+		}
+	}
+
+	if(options->prefix_with_filename == 2)
+		options->prefix_with_filename = (argc - share__optind > 1);
+
+	if(share__optind >= argc && !options->show_long_help && !options->show_version) {
+		flac_fprintf(stderr,"ERROR: you must specify at least one FLAC file;\n");
+		flac_fprintf(stderr,"       metaflac cannot be used as a pipe\n");
+		had_error = true;
+	}
+
+	options->num_files = argc - share__optind;
+
+	if(options->num_files > 0) {
+		unsigned i = 0;
+		if(0 == (options->filenames = safe_malloc_mul_2op_(sizeof(char*), /*times*/options->num_files)))
+			die("out of memory allocating space for file names list");
+		while(share__optind < argc)
+			options->filenames[i++] = local_strdup(argv[share__optind++]);
+	}
+
+	if(options->args.checks.num_major_ops > 0) {
+		if(options->args.checks.num_major_ops > 1) {
+			flac_fprintf(stderr, "ERROR: you may only specify one major operation at a time\n");
+			had_error = true;
+		}
+		else if(options->args.checks.num_shorthand_ops > 0) {
+			flac_fprintf(stderr, "ERROR: you may not mix shorthand and major operations\n");
+			had_error = true;
+		}
+	}
+
+	/* check for only one FLAC file used with certain options */
+	if(options->num_files > 1) {
+		if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) {
+			flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--import-cuesheet-from'\n");
+			had_error = true;
+		}
+		if(0 != find_shorthand_operation(options, OP__EXPORT_CUESHEET_TO)) {
+			flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--export-cuesheet-to'\n");
+			had_error = true;
+		}
+		if(0 != find_shorthand_operation(options, OP__EXPORT_PICTURE_TO)) {
+			flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--export-picture-to'\n");
+			had_error = true;
+		}
+		if(
+			0 != find_shorthand_operation(options, OP__IMPORT_VC_FROM) &&
+			0 == strcmp(find_shorthand_operation(options, OP__IMPORT_VC_FROM)->argument.filename.value, "-")
+		) {
+			flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--import-tags-from=-'\n");
+			had_error = true;
+		}
+	}
+
+	if(options->args.checks.has_block_type && options->args.checks.has_except_block_type) {
+		flac_fprintf(stderr, "ERROR: you may not specify both '--block-type' and '--except-block-type'\n");
+		had_error = true;
+	}
+
+	if(had_error)
+		short_usage(0);
+
+	/*
+	 * We need to create an OP__ADD_SEEKPOINT operation if there is
+	 * not one already, and --import-cuesheet-from was specified but
+	 * --no-cued-seekpoints was not:
+	 */
+	if(options->cued_seekpoints) {
+		Operation *op = find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM);
+		if(0 != op) {
+			Operation *op2 = find_shorthand_operation(options, OP__ADD_SEEKPOINT);
+			if(0 == op2)
+				op2 = append_shorthand_operation(options, OP__ADD_SEEKPOINT);
+			op->argument.import_cuesheet_from.add_seekpoint_link = &(op2->argument.add_seekpoint);
+		}
+	}
+
+	return had_error;
+}
+
+void free_options(CommandLineOptions *options)
+{
+	unsigned i;
+	Operation *op;
+	Argument *arg;
+
+	FLAC__ASSERT(0 == options->ops.operations || options->ops.num_operations > 0);
+	FLAC__ASSERT(0 == options->args.arguments || options->args.num_arguments > 0);
+
+	for(i = 0, op = options->ops.operations; i < options->ops.num_operations; i++, op++) {
+		switch(op->type) {
+			case OP__SHOW_VC_FIELD:
+			case OP__REMOVE_VC_FIELD:
+			case OP__REMOVE_VC_FIRSTFIELD:
+				if(0 != op->argument.vc_field_name.value)
+					free(op->argument.vc_field_name.value);
+				break;
+			case OP__SET_VC_FIELD:
+				if(0 != op->argument.vc_field.field)
+					free(op->argument.vc_field.field);
+				if(0 != op->argument.vc_field.field_name)
+					free(op->argument.vc_field.field_name);
+				if(0 != op->argument.vc_field.field_value)
+					free(op->argument.vc_field.field_value);
+				break;
+			case OP__IMPORT_VC_FROM:
+			case OP__EXPORT_VC_TO:
+			case OP__EXPORT_CUESHEET_TO:
+				if(0 != op->argument.filename.value)
+					free(op->argument.filename.value);
+				break;
+			case OP__IMPORT_CUESHEET_FROM:
+				if(0 != op->argument.import_cuesheet_from.filename)
+					free(op->argument.import_cuesheet_from.filename);
+				break;
+			case OP__IMPORT_PICTURE_FROM:
+				if(0 != op->argument.specification.value)
+					free(op->argument.specification.value);
+				break;
+			case OP__EXPORT_PICTURE_TO:
+				if(0 != op->argument.export_picture_to.filename)
+					free(op->argument.export_picture_to.filename);
+				break;
+			case OP__ADD_SEEKPOINT:
+				if(0 != op->argument.add_seekpoint.specification)
+					free(op->argument.add_seekpoint.specification);
+				break;
+			default:
+				break;
+		}
+	}
+
+	for(i = 0, arg = options->args.arguments; i < options->args.num_arguments; i++, arg++) {
+		switch(arg->type) {
+			case ARG__BLOCK_NUMBER:
+				if(0 != arg->value.block_number.entries)
+					free(arg->value.block_number.entries);
+				break;
+			case ARG__BLOCK_TYPE:
+			case ARG__EXCEPT_BLOCK_TYPE:
+				if(0 != arg->value.block_type.entries)
+					free(arg->value.block_type.entries);
+				break;
+			case ARG__FROM_FILE:
+				if(0 != arg->value.from_file.file_name)
+					free(arg->value.from_file.file_name);
+				break;
+			default:
+				break;
+		}
+	}
+
+	if(0 != options->ops.operations)
+		free(options->ops.operations);
+
+	if(0 != options->args.arguments)
+		free(options->args.arguments);
+
+	if(0 != options->filenames) {
+		for(i = 0; i < options->num_files; i++) {
+			if(0 != options->filenames[i])
+				free(options->filenames[i]);
+		}
+		free(options->filenames);
+	}
+}
+
+/*
+ * local routines
+ */
+
+FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options)
+{
+	const char *opt = long_options_[option_index].name;
+	Operation *op;
+	Argument *arg;
+	FLAC__bool ok = true;
+
+	if(0 == strcmp(opt, "preserve-modtime")) {
+		options->preserve_modtime = true;
+	}
+	else if(0 == strcmp(opt, "with-filename")) {
+		options->prefix_with_filename = true;
+	}
+	else if(0 == strcmp(opt, "no-filename")) {
+		options->prefix_with_filename = false;
+	}
+	else if(0 == strcmp(opt, "no-utf8-convert")) {
+		options->utf8_convert = false;
+	}
+	else if(0 == strcmp(opt, "dont-use-padding")) {
+		options->use_padding = false;
+	}
+	else if(0 == strcmp(opt, "no-cued-seekpoints")) {
+		options->cued_seekpoints = false;
+	}
+	else if(0 == strcmp(opt, "show-md5sum")) {
+		(void) append_shorthand_operation(options, OP__SHOW_MD5SUM);
+	}
+	else if(0 == strcmp(opt, "show-min-blocksize")) {
+		(void) append_shorthand_operation(options, OP__SHOW_MIN_BLOCKSIZE);
+	}
+	else if(0 == strcmp(opt, "show-max-blocksize")) {
+		(void) append_shorthand_operation(options, OP__SHOW_MAX_BLOCKSIZE);
+	}
+	else if(0 == strcmp(opt, "show-min-framesize")) {
+		(void) append_shorthand_operation(options, OP__SHOW_MIN_FRAMESIZE);
+	}
+	else if(0 == strcmp(opt, "show-max-framesize")) {
+		(void) append_shorthand_operation(options, OP__SHOW_MAX_FRAMESIZE);
+	}
+	else if(0 == strcmp(opt, "show-sample-rate")) {
+		(void) append_shorthand_operation(options, OP__SHOW_SAMPLE_RATE);
+	}
+	else if(0 == strcmp(opt, "show-channels")) {
+		(void) append_shorthand_operation(options, OP__SHOW_CHANNELS);
+	}
+	else if(0 == strcmp(opt, "show-bps")) {
+		(void) append_shorthand_operation(options, OP__SHOW_BPS);
+	}
+	else if(0 == strcmp(opt, "show-total-samples")) {
+		(void) append_shorthand_operation(options, OP__SHOW_TOTAL_SAMPLES);
+	}
+	else if(0 == strcmp(opt, "set-md5sum")) {
+		op = append_shorthand_operation(options, OP__SET_MD5SUM);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_md5(option_argument, op->argument.streaminfo_md5.value)) {
+			flac_fprintf(stderr, "ERROR (--%s): bad MD5 sum\n", opt);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "set-min-blocksize")) {
+		op = append_shorthand_operation(options, OP__SET_MIN_BLOCKSIZE);
+		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BLOCK_SIZE || op->argument.streaminfo_uint32.value > FLAC__MAX_BLOCK_SIZE) {
+			flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "set-max-blocksize")) {
+		op = append_shorthand_operation(options, OP__SET_MAX_BLOCKSIZE);
+		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BLOCK_SIZE || op->argument.streaminfo_uint32.value > FLAC__MAX_BLOCK_SIZE) {
+			flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "set-min-framesize")) {
+		op = append_shorthand_operation(options, OP__SET_MIN_FRAMESIZE);
+		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value >= (1u<<FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) {
+			flac_fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "set-max-framesize")) {
+		op = append_shorthand_operation(options, OP__SET_MAX_FRAMESIZE);
+		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value >= (1u<<FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) {
+			flac_fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "set-sample-rate")) {
+		op = append_shorthand_operation(options, OP__SET_SAMPLE_RATE);
+		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || !FLAC__format_sample_rate_is_valid(op->argument.streaminfo_uint32.value)) {
+			flac_fprintf(stderr, "ERROR (--%s): invalid sample rate\n", opt);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "set-channels")) {
+		op = append_shorthand_operation(options, OP__SET_CHANNELS);
+		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value > FLAC__MAX_CHANNELS) {
+			flac_fprintf(stderr, "ERROR (--%s): value must be > 0 and <= %u\n", opt, FLAC__MAX_CHANNELS);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "set-bps")) {
+		op = append_shorthand_operation(options, OP__SET_BPS);
+		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BITS_PER_SAMPLE || op->argument.streaminfo_uint32.value > FLAC__MAX_BITS_PER_SAMPLE) {
+			flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BITS_PER_SAMPLE, FLAC__MAX_BITS_PER_SAMPLE);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "set-total-samples")) {
+		op = append_shorthand_operation(options, OP__SET_TOTAL_SAMPLES);
+		if(!parse_uint64(option_argument, &(op->argument.streaminfo_uint64.value)) || op->argument.streaminfo_uint64.value >= (((FLAC__uint64)1)<<FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) {
+			flac_fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN);
+			ok = false;
+		}
+		else
+			undocumented_warning(opt);
+	}
+	else if(0 == strcmp(opt, "show-vendor-tag")) {
+		(void) append_shorthand_operation(options, OP__SHOW_VC_VENDOR);
+	}
+	else if(0 == strcmp(opt, "show-tag")) {
+		const char *violation;
+		op = append_shorthand_operation(options, OP__SHOW_VC_FIELD);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
+			FLAC__ASSERT(0 != violation);
+			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "remove-all-tags")) {
+		(void) append_shorthand_operation(options, OP__REMOVE_VC_ALL);
+	}
+	else if(0 == strcmp(opt, "remove-tag")) {
+		const char *violation;
+		op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
+			FLAC__ASSERT(0 != violation);
+			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "remove-first-tag")) {
+		const char *violation;
+		op = append_shorthand_operation(options, OP__REMOVE_VC_FIRSTFIELD);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
+			FLAC__ASSERT(0 != violation);
+			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "set-tag")) {
+		const char *violation;
+		op = append_shorthand_operation(options, OP__SET_VC_FIELD);
+		FLAC__ASSERT(0 != option_argument);
+		op->argument.vc_field.field_value_from_file = false;
+		if(!parse_vorbis_comment_field(option_argument, &(op->argument.vc_field.field), &(op->argument.vc_field.field_name), &(op->argument.vc_field.field_value), &(op->argument.vc_field.field_value_length), &violation)) {
+			FLAC__ASSERT(0 != violation);
+			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field \"%s\",\n       %s\n", opt, option_argument, violation);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "set-tag-from-file")) {
+		const char *violation;
+		op = append_shorthand_operation(options, OP__SET_VC_FIELD);
+		FLAC__ASSERT(0 != option_argument);
+		op->argument.vc_field.field_value_from_file = true;
+		if(!parse_vorbis_comment_field(option_argument, &(op->argument.vc_field.field), &(op->argument.vc_field.field_name), &(op->argument.vc_field.field_value), &(op->argument.vc_field.field_value_length), &violation)) {
+			FLAC__ASSERT(0 != violation);
+			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field \"%s\",\n       %s\n", opt, option_argument, violation);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "import-tags-from")) {
+		op = append_shorthand_operation(options, OP__IMPORT_VC_FROM);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_string(option_argument, &(op->argument.filename.value))) {
+			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "export-tags-to")) {
+		op = append_shorthand_operation(options, OP__EXPORT_VC_TO);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_string(option_argument, &(op->argument.filename.value))) {
+			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "import-cuesheet-from")) {
+		if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) {
+			flac_fprintf(stderr, "ERROR (--%s): may be specified only once\n", opt);
+			ok = false;
+		}
+		op = append_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_string(option_argument, &(op->argument.import_cuesheet_from.filename))) {
+			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "export-cuesheet-to")) {
+		op = append_shorthand_operation(options, OP__EXPORT_CUESHEET_TO);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_string(option_argument, &(op->argument.filename.value))) {
+			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "import-picture-from")) {
+		op = append_shorthand_operation(options, OP__IMPORT_PICTURE_FROM);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_string(option_argument, &(op->argument.specification.value))) {
+			flac_fprintf(stderr, "ERROR (--%s): missing specification\n", opt);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "export-picture-to")) {
+		arg = find_argument(options, ARG__BLOCK_NUMBER);
+		op = append_shorthand_operation(options, OP__EXPORT_PICTURE_TO);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_string(option_argument, &(op->argument.export_picture_to.filename))) {
+			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+			ok = false;
+		}
+		op->argument.export_picture_to.block_number_link = arg? &(arg->value.block_number) : 0;
+	}
+	else if(0 == strcmp(opt, "add-seekpoint")) {
+		const char *violation;
+		char *spec;
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_add_seekpoint(option_argument, &spec, &violation)) {
+			FLAC__ASSERT(0 != violation);
+			flac_fprintf(stderr, "ERROR (--%s): malformed seekpoint specification \"%s\",\n       %s\n", opt, option_argument, violation);
+			ok = false;
+		}
+		else {
+			op = find_shorthand_operation(options, OP__ADD_SEEKPOINT);
+			if(0 == op)
+				op = append_shorthand_operation(options, OP__ADD_SEEKPOINT);
+			local_strcat(&(op->argument.add_seekpoint.specification), spec);
+			local_strcat(&(op->argument.add_seekpoint.specification), ";");
+			free(spec);
+		}
+	}
+	else if(0 == strcmp(opt, "add-replay-gain")) {
+		(void) append_shorthand_operation(options, OP__ADD_REPLAY_GAIN);
+	}
+	else if(0 == strcmp(opt, "scan-replay-gain")) {
+		(void) append_shorthand_operation(options, OP__SCAN_REPLAY_GAIN);
+	}
+	else if(0 == strcmp(opt, "remove-replay-gain")) {
+		const FLAC__byte * const tags[5] = {
+			GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS,
+			GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN,
+			GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK,
+			GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN,
+			GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK
+		};
+		size_t i;
+		for(i = 0; i < sizeof(tags)/sizeof(tags[0]); i++) {
+			op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD);
+			op->argument.vc_field_name.value = local_strdup((const char *)tags[i]);
+		}
+	}
+	else if(0 == strcmp(opt, "add-padding")) {
+		op = append_shorthand_operation(options, OP__ADD_PADDING);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_add_padding(option_argument, &(op->argument.add_padding.length))) {
+			flac_fprintf(stderr, "ERROR (--%s): illegal length \"%s\", length must be >= 0 and < 2^%u\n", opt, option_argument, FLAC__STREAM_METADATA_LENGTH_LEN);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "help")) {
+		options->show_long_help = true;
+	}
+	else if(0 == strcmp(opt, "version")) {
+		options->show_version = true;
+	}
+	else if(0 == strcmp(opt, "list")) {
+		(void) append_major_operation(options, OP__LIST);
+	}
+	else if(0 == strcmp(opt, "append")) {
+		(void) append_major_operation(options, OP__APPEND);
+	}
+	else if(0 == strcmp(opt, "remove")) {
+		(void) append_major_operation(options, OP__REMOVE);
+	}
+	else if(0 == strcmp(opt, "remove-all")) {
+		(void) append_major_operation(options, OP__REMOVE_ALL);
+	}
+	else if(0 == strcmp(opt, "merge-padding")) {
+		(void) append_major_operation(options, OP__MERGE_PADDING);
+	}
+	else if(0 == strcmp(opt, "sort-padding")) {
+		(void) append_major_operation(options, OP__SORT_PADDING);
+	}
+	else if(0 == strcmp(opt, "block-number")) {
+		arg = append_argument(options, ARG__BLOCK_NUMBER);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_block_number(option_argument, &(arg->value.block_number))) {
+			flac_fprintf(stderr, "ERROR: malformed block number specification \"%s\"\n", option_argument);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "block-type")) {
+		arg = append_argument(options, ARG__BLOCK_TYPE);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_block_type(option_argument, &(arg->value.block_type))) {
+			flac_fprintf(stderr, "ERROR (--%s): malformed block type specification \"%s\"\n", opt, option_argument);
+			ok = false;
+		}
+		options->args.checks.has_block_type = true;
+	}
+	else if(0 == strcmp(opt, "except-block-type")) {
+		arg = append_argument(options, ARG__EXCEPT_BLOCK_TYPE);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_block_type(option_argument, &(arg->value.block_type))) {
+			flac_fprintf(stderr, "ERROR (--%s): malformed block type specification \"%s\"\n", opt, option_argument);
+			ok = false;
+		}
+		options->args.checks.has_except_block_type = true;
+	}
+	else if(0 == strcmp(opt, "data-format")) {
+		arg = append_argument(options, ARG__DATA_FORMAT);
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_data_format(option_argument, &(arg->value.data_format))) {
+			flac_fprintf(stderr, "ERROR (--%s): illegal data format \"%s\"\n", opt, option_argument);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "application-data-format")) {
+		FLAC__ASSERT(0 != option_argument);
+		if(!parse_application_data_format(option_argument, &(options->application_data_format_is_hexdump))) {
+			flac_fprintf(stderr, "ERROR (--%s): illegal application data format \"%s\"\n", opt, option_argument);
+			ok = false;
+		}
+	}
+	else if(0 == strcmp(opt, "from-file")) {
+		arg = append_argument(options, ARG__FROM_FILE);
+		FLAC__ASSERT(0 != option_argument);
+		arg->value.from_file.file_name = local_strdup(option_argument);
+	}
+	else {
+		FLAC__ASSERT(0);
+	}
+
+	return ok;
+}
+
+void append_new_operation(CommandLineOptions *options, Operation operation)
+{
+	if(options->ops.capacity == 0) {
+		options->ops.capacity = 50;
+		if(0 == (options->ops.operations = malloc(sizeof(Operation) * options->ops.capacity)))
+			die("out of memory allocating space for option list");
+		memset(options->ops.operations, 0, sizeof(Operation) * options->ops.capacity);
+	}
+	if(options->ops.capacity <= options->ops.num_operations) {
+		unsigned original_capacity = options->ops.capacity;
+		if(options->ops.capacity > UINT32_MAX / 2) /* overflow check */
+			die("out of memory allocating space for option list");
+		options->ops.capacity *= 2;
+		if(0 == (options->ops.operations = safe_realloc_mul_2op_(options->ops.operations, sizeof(Operation), /*times*/options->ops.capacity)))
+			die("out of memory allocating space for option list");
+		memset(options->ops.operations + original_capacity, 0, sizeof(Operation) * (options->ops.capacity - original_capacity));
+	}
+
+	options->ops.operations[options->ops.num_operations++] = operation;
+}
+
+void append_new_argument(CommandLineOptions *options, Argument argument)
+{
+	if(options->args.capacity == 0) {
+		options->args.capacity = 50;
+		if(0 == (options->args.arguments = malloc(sizeof(Argument) * options->args.capacity)))
+			die("out of memory allocating space for option list");
+		memset(options->args.arguments, 0, sizeof(Argument) * options->args.capacity);
+	}
+	if(options->args.capacity <= options->args.num_arguments) {
+		unsigned original_capacity = options->args.capacity;
+		if(options->args.capacity > UINT32_MAX / 2) /* overflow check */
+			die("out of memory allocating space for option list");
+		options->args.capacity *= 2;
+		if(0 == (options->args.arguments = safe_realloc_mul_2op_(options->args.arguments, sizeof(Argument), /*times*/options->args.capacity)))
+			die("out of memory allocating space for option list");
+		memset(options->args.arguments + original_capacity, 0, sizeof(Argument) * (options->args.capacity - original_capacity));
+	}
+
+	options->args.arguments[options->args.num_arguments++] = argument;
+}
+
+Operation *append_major_operation(CommandLineOptions *options, OperationType type)
+{
+	Operation op;
+	memset(&op, 0, sizeof(op));
+	op.type = type;
+	append_new_operation(options, op);
+	options->args.checks.num_major_ops++;
+	return options->ops.operations + (options->ops.num_operations - 1);
+}
+
+Operation *append_shorthand_operation(CommandLineOptions *options, OperationType type)
+{
+	Operation op;
+	memset(&op, 0, sizeof(op));
+	op.type = type;
+	append_new_operation(options, op);
+	options->args.checks.num_shorthand_ops++;
+	return options->ops.operations + (options->ops.num_operations - 1);
+}
+
+Argument *find_argument(CommandLineOptions *options, ArgumentType type)
+{
+	unsigned i;
+	for(i = 0; i < options->args.num_arguments; i++)
+		if(options->args.arguments[i].type == type)
+			return &options->args.arguments[i];
+	return 0;
+}
+
+Operation *find_shorthand_operation(CommandLineOptions *options, OperationType type)
+{
+	unsigned i;
+	for(i = 0; i < options->ops.num_operations; i++)
+		if(options->ops.operations[i].type == type)
+			return &options->ops.operations[i];
+	return 0;
+}
+
+Argument *append_argument(CommandLineOptions *options, ArgumentType type)
+{
+	Argument arg;
+	memset(&arg, 0, sizeof(arg));
+	arg.type = type;
+	append_new_argument(options, arg);
+	return options->args.arguments + (options->args.num_arguments - 1);
+}
+
+FLAC__bool parse_md5(const char *src, FLAC__byte dest[16])
+{
+	unsigned i, d;
+	int c;
+	FLAC__ASSERT(0 != src);
+	if(strlen(src) != 32)
+		return false;
+	/* strtoul() accepts negative numbers which we do not want, so we do it the hard way */
+	for(i = 0; i < 16; i++) {
+		c = (int)(*src++);
+		if(isdigit(c))
+			d = (unsigned)(c - '0');
+		else if(c >= 'a' && c <= 'f')
+			d = (unsigned)(c - 'a') + 10u;
+		else if(c >= 'A' && c <= 'F')
+			d = (unsigned)(c - 'A') + 10u;
+		else
+			return false;
+		d <<= 4;
+		c = (int)(*src++);
+		if(isdigit(c))
+			d |= (unsigned)(c - '0');
+		else if(c >= 'a' && c <= 'f')
+			d |= (unsigned)(c - 'a') + 10u;
+		else if(c >= 'A' && c <= 'F')
+			d |= (unsigned)(c - 'A') + 10u;
+		else
+			return false;
+		dest[i] = (FLAC__byte)d;
+	}
+	return true;
+}
+
+FLAC__bool parse_uint32(const char *src, FLAC__uint32 *dest)
+{
+	FLAC__ASSERT(0 != src);
+	if(strlen(src) == 0 || strspn(src, "0123456789") != strlen(src))
+		return false;
+	*dest = strtoul(src, 0, 10);
+	return true;
+}
+
+FLAC__bool parse_uint64(const char *src, FLAC__uint64 *dest)
+{
+	FLAC__ASSERT(0 != src);
+	if(strlen(src) == 0 || strspn(src, "0123456789") != strlen(src))
+		return false;
+	*dest = strtoull(src, 0, 10);
+	return true;
+}
+
+FLAC__bool parse_string(const char *src, char **dest)
+{
+	if(0 == src || strlen(src) == 0)
+		return false;
+	*dest = strdup(src);
+	return true;
+}
+
+FLAC__bool parse_vorbis_comment_field_name(const char *field_ref, char **name, const char **violation)
+{
+	static const char * const violations[] = {
+		"field name contains invalid character"
+	};
+
+	char *q, *s;
+
+	s = local_strdup(field_ref);
+
+	for(q = s; *q; q++) {
+		if(*q < 0x20 || *q > 0x7d || *q == 0x3d) {
+			free(s);
+			*violation = violations[0];
+			return false;
+		}
+	}
+
+	*name = s;
+
+	return true;
+}
+
+FLAC__bool parse_add_seekpoint(const char *in, char **out, const char **violation)
+{
+	static const char *garbled_ = "garbled specification";
+	const unsigned n = strlen(in);
+
+	FLAC__ASSERT(0 != in);
+	FLAC__ASSERT(0 != out);
+
+	if(n == 0) {
+		*violation = "specification is empty";
+		return false;
+	}
+
+	if(n > strspn(in, "0123456789.Xsx")) {
+		*violation = "specification contains invalid character";
+		return false;
+	}
+
+	if(in[n-1] == 'X') {
+		if(n > 1) {
+			*violation = garbled_;
+			return false;
+		}
+	}
+	else if(in[n-1] == 's') {
+		if(n-1 > strspn(in, "0123456789.")) {
+			*violation = garbled_;
+			return false;
+		}
+	}
+	else if(in[n-1] == 'x') {
+		if(n-1 > strspn(in, "0123456789")) {
+			*violation = garbled_;
+			return false;
+		}
+	}
+	else {
+		if(n > strspn(in, "0123456789")) {
+			*violation = garbled_;
+			return false;
+		}
+	}
+
+	*out = local_strdup(in);
+	return true;
+}
+
+FLAC__bool parse_add_padding(const char *in, unsigned *out)
+{
+	FLAC__ASSERT(0 != in);
+	FLAC__ASSERT(0 != out);
+	*out = (unsigned)strtoul(in, 0, 10);
+	return *out < (1u << FLAC__STREAM_METADATA_LENGTH_LEN);
+}
+
+FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out)
+{
+	char *p, *q, *s, *end;
+	long i;
+	unsigned entry;
+
+	if(*in == '\0')
+		return false;
+
+	s = local_strdup(in);
+
+	/* first count the entries */
+	for(out->num_entries = 1, p = strchr(s, ','); p; out->num_entries++, p = strchr(++p, ','))
+		;
+
+	/* make space */
+	FLAC__ASSERT(out->num_entries > 0);
+	if(0 == (out->entries = safe_malloc_mul_2op_(sizeof(unsigned), /*times*/out->num_entries)))
+		die("out of memory allocating space for option list");
+
+	/* load 'em up */
+	entry = 0;
+	q = s;
+	while(q) {
+		FLAC__ASSERT(entry < out->num_entries);
+		if(0 != (p = strchr(q, ',')))
+			*p++ = '\0';
+		if(!isdigit((int)(*q)) || (i = strtol(q, &end, 10)) < 0 || *end) {
+			free(s);
+			return false;
+		}
+		out->entries[entry++] = (unsigned)i;
+		q = p;
+	}
+	FLAC__ASSERT(entry == out->num_entries);
+
+	free(s);
+	return true;
+}
+
+FLAC__bool parse_block_type(const char *in, Argument_BlockType *out)
+{
+	char *p, *q, *r, *s;
+	unsigned entry;
+
+	if(*in == '\0')
+		return false;
+
+	s = local_strdup(in);
+
+	/* first count the entries */
+	for(out->num_entries = 1, p = strchr(s, ','); p; out->num_entries++, p = strchr(++p, ','))
+		;
+
+	/* make space */
+	FLAC__ASSERT(out->num_entries > 0);
+	if(0 == (out->entries = safe_malloc_mul_2op_(sizeof(Argument_BlockTypeEntry), /*times*/out->num_entries)))
+		die("out of memory allocating space for option list");
+
+	/* load 'em up */
+	entry = 0;
+	q = s;
+	while(q) {
+		FLAC__ASSERT(entry < out->num_entries);
+		if(0 != (p = strchr(q, ',')))
+			*p++ = 0;
+		r = strchr(q, ':');
+		if(r)
+			*r++ = '\0';
+		if(0 != r && 0 != strcmp(q, "APPLICATION")) {
+			free(s);
+			return false;
+		}
+		if(0 == strcmp(q, "STREAMINFO")) {
+			out->entries[entry++].type = FLAC__METADATA_TYPE_STREAMINFO;
+		}
+		else if(0 == strcmp(q, "PADDING")) {
+			out->entries[entry++].type = FLAC__METADATA_TYPE_PADDING;
+		}
+		else if(0 == strcmp(q, "APPLICATION")) {
+			out->entries[entry].type = FLAC__METADATA_TYPE_APPLICATION;
+			out->entries[entry].filter_application_by_id = (0 != r);
+			if(0 != r) {
+				if(strlen(r) == sizeof (out->entries[entry].application_id)) {
+					memcpy(out->entries[entry].application_id, r, sizeof (out->entries[entry].application_id));
+				}
+				else if(strlen(r) == 10 && FLAC__STRNCASECMP(r, "0x", 2) == 0 && strspn(r+2, "0123456789ABCDEFabcdef") == 8) {
+					FLAC__uint32 x = strtoul(r+2, 0, 16);
+					out->entries[entry].application_id[3] = (FLAC__byte)(x & 0xff);
+					out->entries[entry].application_id[2] = (FLAC__byte)((x>>=8) & 0xff);
+					out->entries[entry].application_id[1] = (FLAC__byte)((x>>=8) & 0xff);
+					out->entries[entry].application_id[0] = (FLAC__byte)((x>>=8) & 0xff);
+				}
+				else {
+					free(s);
+					return false;
+				}
+			}
+			entry++;
+		}
+		else if(0 == strcmp(q, "SEEKTABLE")) {
+			out->entries[entry++].type = FLAC__METADATA_TYPE_SEEKTABLE;
+		}
+		else if(0 == strcmp(q, "VORBIS_COMMENT")) {
+			out->entries[entry++].type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+		}
+		else if(0 == strcmp(q, "CUESHEET")) {
+			out->entries[entry++].type = FLAC__METADATA_TYPE_CUESHEET;
+		}
+		else if(0 == strcmp(q, "PICTURE")) {
+			out->entries[entry++].type = FLAC__METADATA_TYPE_PICTURE;
+		}
+		else {
+			free(s);
+			return false;
+		}
+		q = p;
+	}
+	FLAC__ASSERT(entry == out->num_entries);
+
+	free(s);
+	return true;
+}
+
+FLAC__bool parse_data_format(const char *in, Argument_DataFormat *out)
+{
+	if(0 == strcmp(in, "binary"))
+		out->is_binary = true;
+	else if(0 == strcmp(in, "text"))
+		out->is_binary = false;
+	else
+		return false;
+	return true;
+}
+
+FLAC__bool parse_application_data_format(const char *in, FLAC__bool *out)
+{
+	if(0 == strcmp(in, "hexdump"))
+		*out = true;
+	else if(0 == strcmp(in, "text"))
+		*out = false;
+	else
+		return false;
+	return true;
+}
+
+void undocumented_warning(const char *opt)
+{
+	flac_fprintf(stderr, "WARNING: undocumented option --%s should be used with caution,\n         only for repairing a damaged STREAMINFO block\n", opt);
+}
diff --git a/src/metaflac/options.h b/src/metaflac/options.h
new file mode 100644
index 0000000..7187e65
--- /dev/null
+++ b/src/metaflac/options.h
@@ -0,0 +1,217 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef metaflac__options_h
+#define metaflac__options_h
+
+#include "FLAC/format.h"
+
+#if 0
+/*[JEC] was:#if HAVE_GETOPT_LONG*/
+/*[JEC] see flac/include/share/getopt.h as to why the change */
+#  include <getopt.h>
+#else
+#  include "share/getopt.h"
+#endif
+
+extern struct share__option long_options_[];
+
+typedef enum {
+	OP__SHOW_MD5SUM,
+	OP__SHOW_MIN_BLOCKSIZE,
+	OP__SHOW_MAX_BLOCKSIZE,
+	OP__SHOW_MIN_FRAMESIZE,
+	OP__SHOW_MAX_FRAMESIZE,
+	OP__SHOW_SAMPLE_RATE,
+	OP__SHOW_CHANNELS,
+	OP__SHOW_BPS,
+	OP__SHOW_TOTAL_SAMPLES,
+	OP__SET_MD5SUM,
+	OP__SET_MIN_BLOCKSIZE,
+	OP__SET_MAX_BLOCKSIZE,
+	OP__SET_MIN_FRAMESIZE,
+	OP__SET_MAX_FRAMESIZE,
+	OP__SET_SAMPLE_RATE,
+	OP__SET_CHANNELS,
+	OP__SET_BPS,
+	OP__SET_TOTAL_SAMPLES,
+	OP__SHOW_VC_VENDOR,
+	OP__SHOW_VC_FIELD,
+	OP__REMOVE_VC_ALL,
+	OP__REMOVE_VC_FIELD,
+	OP__REMOVE_VC_FIRSTFIELD,
+	OP__SET_VC_FIELD,
+	OP__IMPORT_VC_FROM,
+	OP__EXPORT_VC_TO,
+	OP__IMPORT_CUESHEET_FROM,
+	OP__EXPORT_CUESHEET_TO,
+	OP__IMPORT_PICTURE_FROM,
+	OP__EXPORT_PICTURE_TO,
+	OP__ADD_SEEKPOINT,
+	OP__ADD_REPLAY_GAIN,
+	OP__SCAN_REPLAY_GAIN,
+	OP__ADD_PADDING,
+	OP__LIST,
+	OP__APPEND,
+	OP__REMOVE,
+	OP__REMOVE_ALL,
+	OP__MERGE_PADDING,
+	OP__SORT_PADDING
+} OperationType;
+
+typedef enum {
+	ARG__BLOCK_NUMBER,
+	ARG__BLOCK_TYPE,
+	ARG__EXCEPT_BLOCK_TYPE,
+	ARG__DATA_FORMAT,
+	ARG__FROM_FILE
+} ArgumentType;
+
+typedef struct {
+	FLAC__byte value[16];
+} Argument_StreaminfoMD5;
+
+typedef struct {
+	FLAC__uint32 value;
+} Argument_StreaminfoUInt32;
+
+typedef struct {
+	FLAC__uint64 value;
+} Argument_StreaminfoUInt64;
+
+typedef struct {
+	char *value;
+} Argument_VcFieldName;
+
+typedef struct {
+	char *field; /* the whole field as passed on the command line, i.e. "NAME=VALUE" */
+	char *field_name;
+	/* according to the vorbis spec, field values can contain \0 so simple C strings are not enough here */
+	unsigned field_value_length;
+	char *field_value;
+	FLAC__bool field_value_from_file; /* true if field_value holds a filename for the value, false for plain value */
+} Argument_VcField;
+
+typedef struct {
+	char *value;
+} Argument_String;
+
+typedef struct {
+	unsigned num_entries;
+	unsigned *entries;
+} Argument_BlockNumber;
+
+typedef struct {
+	FLAC__MetadataType type;
+	char application_id[4]; /* only relevant if type == FLAC__STREAM_METADATA_TYPE_APPLICATION */
+	FLAC__bool filter_application_by_id;
+} Argument_BlockTypeEntry;
+
+typedef struct {
+	unsigned num_entries;
+	Argument_BlockTypeEntry *entries;
+} Argument_BlockType;
+
+typedef struct {
+	FLAC__bool is_binary;
+} Argument_DataFormat;
+
+typedef struct {
+	char *file_name;
+} Argument_FromFile;
+
+typedef struct {
+	char *specification;
+} Argument_AddSeekpoint;
+
+typedef struct {
+	char *filename;
+	Argument_AddSeekpoint *add_seekpoint_link;
+} Argument_ImportCuesheetFrom;
+
+typedef struct {
+	char *filename;
+	const Argument_BlockNumber *block_number_link; /* may be NULL to mean 'first PICTURE block' */
+} Argument_ExportPictureTo;
+
+typedef struct {
+	unsigned length;
+} Argument_AddPadding;
+
+typedef struct {
+	OperationType type;
+	union {
+		Argument_StreaminfoMD5 streaminfo_md5;
+		Argument_StreaminfoUInt32 streaminfo_uint32;
+		Argument_StreaminfoUInt64 streaminfo_uint64;
+		Argument_VcFieldName vc_field_name;
+		Argument_VcField vc_field;
+		Argument_String filename;
+		Argument_String specification;
+		Argument_ImportCuesheetFrom import_cuesheet_from;
+		Argument_ExportPictureTo export_picture_to;
+		Argument_AddSeekpoint add_seekpoint;
+		Argument_AddPadding add_padding;
+	} argument;
+} Operation;
+
+typedef struct {
+	ArgumentType type;
+	union {
+		Argument_BlockNumber block_number;
+		Argument_BlockType block_type;
+		Argument_DataFormat data_format;
+		Argument_FromFile from_file;
+	} value;
+} Argument;
+
+typedef struct {
+	FLAC__bool preserve_modtime;
+	FLAC__bool prefix_with_filename;
+	FLAC__bool utf8_convert;
+	FLAC__bool use_padding;
+	FLAC__bool cued_seekpoints;
+	FLAC__bool show_long_help;
+	FLAC__bool show_version;
+	FLAC__bool application_data_format_is_hexdump;
+	struct {
+		Operation *operations;
+		unsigned num_operations;
+		unsigned capacity;
+	} ops;
+	struct {
+		struct {
+			unsigned num_shorthand_ops;
+			unsigned num_major_ops;
+			FLAC__bool has_block_type;
+			FLAC__bool has_except_block_type;
+		} checks;
+		Argument *arguments;
+		unsigned num_arguments;
+		unsigned capacity;
+	} args;
+	unsigned num_files;
+	char **filenames;
+} CommandLineOptions;
+
+void init_options(CommandLineOptions *options);
+FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options);
+void free_options(CommandLineOptions *options);
+
+#endif
diff --git a/src/metaflac/usage.c b/src/metaflac/usage.c
new file mode 100644
index 0000000..46c3948
--- /dev/null
+++ b/src/metaflac/usage.c
@@ -0,0 +1,330 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "usage.h"
+#include "FLAC/format.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include "share/compat.h"
+
+static void usage_header(FILE *out)
+{
+	fprintf(out, "==============================================================================\n");
+	fprintf(out, "metaflac - Command-line FLAC metadata editor version %s\n", FLAC__VERSION_STRING);
+	fprintf(out, "Copyright (C) 2001-2009  Josh Coalson\n");
+	fprintf(out, "Copyright (C) 2011-2016  Xiph.Org Foundation\n");
+	fprintf(out, "\n");
+	fprintf(out, "This program is free software; you can redistribute it and/or\n");
+	fprintf(out, "modify it under the terms of the GNU General Public License\n");
+	fprintf(out, "as published by the Free Software Foundation; either version 2\n");
+	fprintf(out, "of the License, or (at your option) any later version.\n");
+	fprintf(out, "\n");
+	fprintf(out, "This program is distributed in the hope that it will be useful,\n");
+	fprintf(out, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
+	fprintf(out, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
+	fprintf(out, "GNU General Public License for more details.\n");
+	fprintf(out, "\n");
+	fprintf(out, "You should have received a copy of the GNU General Public License along\n");
+	fprintf(out, "with this program; if not, write to the Free Software Foundation, Inc.,\n");
+	fprintf(out, "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n");
+	fprintf(out, "==============================================================================\n");
+}
+
+static void usage_summary(FILE *out)
+{
+	fprintf(out, "Usage:\n");
+	fprintf(out, "  metaflac [options] [operations] FLACfile [FLACfile ...]\n");
+	fprintf(out, "\n");
+	fprintf(out, "Use metaflac to list, add, remove, or edit metadata in one or more FLAC files.\n");
+	fprintf(out, "You may perform one major operation, or many shorthand operations at a time.\n");
+	fprintf(out, "\n");
+	fprintf(out, "Options:\n");
+	fprintf(out, "--preserve-modtime    Preserve the original modification time in spite of edits\n");
+	fprintf(out, "--with-filename       Prefix each output line with the FLAC file name\n");
+	fprintf(out, "                      (the default if more than one FLAC file is specified)\n");
+	fprintf(out, "--no-filename         Do not prefix each output line with the FLAC file name\n");
+	fprintf(out, "                      (the default if only one FLAC file is specified)\n");
+	fprintf(out, "--no-utf8-convert     Do not convert tags from UTF-8 to local charset,\n");
+	fprintf(out, "                      or vice versa.  This is useful for scripts, and setting\n");
+	fprintf(out, "                      tags in situations where the locale is wrong.\n");
+	fprintf(out, "--dont-use-padding    By default metaflac tries to use padding where possible\n");
+	fprintf(out, "                      to avoid rewriting the entire file if the metadata size\n");
+	fprintf(out, "                      changes.  Use this option to tell metaflac to not take\n");
+	fprintf(out, "                      advantage of padding this way.\n");
+}
+
+int short_usage(const char *message, ...)
+{
+	va_list args;
+
+	if(message) {
+		va_start(args, message);
+
+		(void) vfprintf(stderr, message, args);
+
+		va_end(args);
+
+	}
+	usage_header(stderr);
+	flac_fprintf(stderr, "\n");
+	flac_fprintf(stderr, "This is the short help; for full help use 'metaflac --help'\n");
+	flac_fprintf(stderr, "\n");
+	usage_summary(stderr);
+
+	return message? 1 : 0;
+}
+
+int long_usage(const char *message, ...)
+{
+	FILE *out = (message? stderr : stdout);
+	va_list args;
+
+	if(message) {
+		va_start(args, message);
+
+		(void) vfprintf(stderr, message, args);
+
+		va_end(args);
+
+	}
+	usage_header(out);
+	fprintf(out, "\n");
+	usage_summary(out);
+	fprintf(out, "\n");
+	fprintf(out, "Shorthand operations:\n");
+	fprintf(out, "--show-md5sum         Show the MD5 signature from the STREAMINFO block.\n");
+	fprintf(out, "--show-min-blocksize  Show the minimum block size from the STREAMINFO block.\n");
+	fprintf(out, "--show-max-blocksize  Show the maximum block size from the STREAMINFO block.\n");
+	fprintf(out, "--show-min-framesize  Show the minimum frame size from the STREAMINFO block.\n");
+	fprintf(out, "--show-max-framesize  Show the maximum frame size from the STREAMINFO block.\n");
+	fprintf(out, "--show-sample-rate    Show the sample rate from the STREAMINFO block.\n");
+	fprintf(out, "--show-channels       Show the number of channels from the STREAMINFO block.\n");
+	fprintf(out, "--show-bps            Show the # of bits per sample from the STREAMINFO block.\n");
+	fprintf(out, "--show-total-samples  Show the total # of samples from the STREAMINFO block.\n");
+	fprintf(out, "\n");
+	fprintf(out, "--show-vendor-tag     Show the vendor string from the VORBIS_COMMENT block.\n");
+	fprintf(out, "--show-tag=NAME       Show all tags where the field name matches 'NAME'.\n");
+	fprintf(out, "--remove-tag=NAME     Remove all tags whose field name is 'NAME'.\n");
+	fprintf(out, "--remove-first-tag=NAME  Remove first tag whose field name is 'NAME'.\n");
+	fprintf(out, "--remove-all-tags     Remove all tags, leaving only the vendor string.\n");
+	fprintf(out, "--set-tag=FIELD       Add a tag.  The FIELD must comply with the Vorbis comment\n");
+	fprintf(out, "                      spec, of the form \"NAME=VALUE\".  If there is currently\n");
+	fprintf(out, "                      no tag block, one will be created.\n");
+	fprintf(out, "--set-tag-from-file=FIELD   Like --set-tag, except the VALUE is a filename\n");
+	fprintf(out, "                      whose contents will be read verbatim to set the tag value.\n");
+	fprintf(out, "                      Unless --no-utf8-convert is specified, the contents will\n");
+	fprintf(out, "                      be converted to UTF-8 from the local charset.  This can\n");
+	fprintf(out, "                      be used to store a cuesheet in a tag (e.g.\n");
+	fprintf(out, "                      --set-tag-from-file=\"CUESHEET=image.cue\").  Do not try\n");
+	fprintf(out, "                      to store binary data in tag fields!  Use APPLICATION\n");
+	fprintf(out, "                      blocks for that.\n");
+	fprintf(out, "--import-tags-from=FILE Import tags from a file.  Use '-' for stdin.  Each line\n");
+	fprintf(out, "                      should be of the form NAME=VALUE.  Multi-line comments\n");
+	fprintf(out, "                      are currently not supported.  Specify --remove-all-tags\n");
+	fprintf(out, "                      and/or --no-utf8-convert before --import-tags-from if\n");
+	fprintf(out, "                      necessary.  If FILE is '-' (stdin), only one FLAC file\n");
+	fprintf(out, "                      may be specified.\n");
+	fprintf(out, "--export-tags-to=FILE Export tags to a file.  Use '-' for stdout.  Each line\n");
+	fprintf(out, "                      will be of the form NAME=VALUE.  Specify\n");
+	fprintf(out, "                      --no-utf8-convert if necessary.\n");
+	fprintf(out, "--import-cuesheet-from=FILE  Import a cuesheet from a file.  Use '-' for stdin.\n");
+	fprintf(out, "                      Only one FLAC file may be specified.  A seekpoint will be\n");
+	fprintf(out, "                      added for each index point in the cuesheet to the\n");
+	fprintf(out, "                      SEEKTABLE unless --no-cued-seekpoints is specified.\n");
+	fprintf(out, "--export-cuesheet-to=FILE  Export CUESHEET block to a cuesheet file, suitable\n");
+	fprintf(out, "                      for use by CD authoring software.  Use '-' for stdout.\n");
+	fprintf(out, "                      Only one FLAC file may be specified on the command line.\n");
+	fprintf(out, "--import-picture-from=FILENAME|SPECIFICATION  Import a picture and store it in a\n");
+	fprintf(out, "                      PICTURE block.  Either a filename for the picture file or\n");
+	fprintf(out, "                      a more complete specification form can be used.  The\n");
+	fprintf(out, "                      SPECIFICATION is a string whose parts are separated by |\n");
+	fprintf(out, "                      characters.  Some parts may be left empty to invoke\n");
+	fprintf(out, "                      default values.  FILENAME is just shorthand for\n");
+	fprintf(out, "                      \"||||FILENAME\".  The format of SPECIFICATION is:\n");
+	fprintf(out, "         [TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE\n");
+	fprintf(out, "           TYPE is optional; it is a number from one of:\n");
+	fprintf(out, "              0: Other\n");
+	fprintf(out, "              1: 32x32 pixels 'file icon' (PNG only)\n");
+	fprintf(out, "              2: Other file icon\n");
+	fprintf(out, "              3: Cover (front)\n");
+	fprintf(out, "              4: Cover (back)\n");
+	fprintf(out, "              5: Leaflet page\n");
+	fprintf(out, "              6: Media (e.g. label side of CD)\n");
+	fprintf(out, "              7: Lead artist/lead performer/soloist\n");
+	fprintf(out, "              8: Artist/performer\n");
+	fprintf(out, "              9: Conductor\n");
+	fprintf(out, "             10: Band/Orchestra\n");
+	fprintf(out, "             11: Composer\n");
+	fprintf(out, "             12: Lyricist/text writer\n");
+	fprintf(out, "             13: Recording Location\n");
+	fprintf(out, "             14: During recording\n");
+	fprintf(out, "             15: During performance\n");
+	fprintf(out, "             16: Movie/video screen capture\n");
+	fprintf(out, "             17: A bright coloured fish\n");
+	fprintf(out, "             18: Illustration\n");
+	fprintf(out, "             19: Band/artist logotype\n");
+	fprintf(out, "             20: Publisher/Studio logotype\n");
+	fprintf(out, "             The default is 3 (front cover).  There may only be one picture each\n");
+	fprintf(out, "             of type 1 and 2 in a file.\n");
+	fprintf(out, "           MIME-TYPE is optional; if left blank, it will be detected from the\n");
+	fprintf(out, "             file.  For best compatibility with players, use pictures with MIME\n");
+	fprintf(out, "             type image/jpeg or image/png.  The MIME type can also be --> to\n");
+	fprintf(out, "             mean that FILE is actually a URL to an image, though this use is\n");
+	fprintf(out, "             discouraged.\n");
+	fprintf(out, "           DESCRIPTION is optional; the default is an empty string\n");
+	fprintf(out, "           The next part specifies the resolution and color information.  If\n");
+	fprintf(out, "             the MIME-TYPE is image/jpeg, image/png, or image/gif, you can\n");
+	fprintf(out, "             usually leave this empty and they can be detected from the file.\n");
+	fprintf(out, "             Otherwise, you must specify the width in pixels, height in pixels,\n");
+	fprintf(out, "             and color depth in bits-per-pixel.  If the image has indexed colors\n");
+	fprintf(out, "             you should also specify the number of colors used.\n");
+	fprintf(out, "           FILE is the path to the picture file to be imported, or the URL if\n");
+	fprintf(out, "             MIME type is -->\n");
+	fprintf(out, "--export-picture-to=FILE  Export PICTURE block to a file.  Use '-' for stdout.\n");
+	fprintf(out, "                      Only one FLAC file may be specified.  The first PICTURE\n");
+	fprintf(out, "                      block will be exported unless --export-picture-to is\n");
+	fprintf(out, "                      preceded by a --block-number=# option to specify the exact\n");
+	fprintf(out, "                      metadata block to extract.  Note that the block number is\n");
+	fprintf(out, "                      the one shown by --list.\n");
+	fprintf(out, "--add-replay-gain     Calculates the title and album gains/peaks of the given\n");
+	fprintf(out, "                      FLAC files as if all the files were part of one album,\n");
+	fprintf(out, "                      then stores them in the VORBIS_COMMENT block.  The tags\n");
+	fprintf(out, "                      are the same as those used by vorbisgain.  Existing\n");
+	fprintf(out, "                      ReplayGain tags will be replaced.  If only one FLAC file\n");
+	fprintf(out, "                      is given, the album and title gains will be the same.\n");
+	fprintf(out, "                      Since this operation requires two passes, it is always\n");
+	fprintf(out, "                      executed last, after all other operations have been\n");
+	fprintf(out, "                      completed and written to disk.  All FLAC files specified\n");
+	fprintf(out, "                      must have the same resolution, sample rate, and number\n");
+	fprintf(out, "                      of channels.  The sample rate must be one of 8, 11.025,\n");
+	fprintf(out, "                      12, 16, 22.05, 24, 32, 44.1, or 48 kHz.\n");
+	fprintf(out, "--scan-replay-gain    Like --add-replay-gain, but only analyzes the files\n");
+	fprintf(out, "                      rather than writing them to tags.\n");
+	fprintf(out, "--remove-replay-gain  Removes the ReplayGain tags.\n");
+	fprintf(out, "--add-seekpoint={#|X|#x|#s}  Add seek points to a SEEKTABLE block\n");
+	fprintf(out, "       #  : a specific sample number for a seek point\n");
+	fprintf(out, "       X  : a placeholder point (always goes at the end of the SEEKTABLE)\n");
+	fprintf(out, "       #x : # evenly spaced seekpoints, the first being at sample 0\n");
+	fprintf(out, "       #s : a seekpoint every # seconds; # does not have to be a whole number\n");
+	fprintf(out, "                      If no SEEKTABLE block exists, one will be created.  If\n");
+	fprintf(out, "                      one already exists, points will be added to the existing\n");
+	fprintf(out, "                      table, and any duplicates will be turned into placeholder\n");
+	fprintf(out, "                      points.  You may use many --add-seekpoint options; the\n");
+	fprintf(out, "                      resulting SEEKTABLE will be the unique-ified union of\n");
+	fprintf(out, "                      all such values.  Example: --add-seekpoint=100x\n");
+	fprintf(out, "                      --add-seekpoint=3.5s will add 100 evenly spaced\n");
+	fprintf(out, "                      seekpoints and a seekpoint every 3.5 seconds.\n");
+	fprintf(out, "--add-padding=length  Add a padding block of the given length (in bytes).\n");
+	fprintf(out, "                      The overall length of the new block will be 4 + length;\n");
+	fprintf(out, "                      the extra 4 bytes is for the metadata block header.\n");
+	fprintf(out, "\n");
+	fprintf(out, "Major operations:\n");
+	fprintf(out, "--version\n");
+	fprintf(out, "    Show the metaflac version number.\n");
+	fprintf(out, "--list\n");
+	fprintf(out, "    List the contents of one or more metadata blocks to stdout.  By default,\n");
+	fprintf(out, "    all metadata blocks are listed in text format.  Use the following options\n");
+	fprintf(out, "    to change this behavior:\n");
+	fprintf(out, "\n");
+	fprintf(out, "    --block-number=#[,#[...]]\n");
+	fprintf(out, "    An optional comma-separated list of block numbers to display.  The first\n");
+	fprintf(out, "    block, the STREAMINFO block, is block 0.\n");
+	fprintf(out, "\n");
+	fprintf(out, "    --block-type=type[,type[...]]\n");
+	fprintf(out, "    --except-block-type=type[,type[...]]\n");
+	fprintf(out, "    An optional comma-separated list of block types to be included or ignored\n");
+	fprintf(out, "    with this option.  Use only one of --block-type or --except-block-type.\n");
+	fprintf(out, "    The valid block types are: STREAMINFO, PADDING, APPLICATION, SEEKTABLE,\n");
+	fprintf(out, "    VORBIS_COMMENT.  You may narrow down the types of APPLICATION blocks\n");
+	fprintf(out, "    displayed as follows:\n");
+	fprintf(out, "        APPLICATION:abcd        The APPLICATION block(s) whose textual repre-\n");
+	fprintf(out, "                                sentation of the 4-byte ID is \"abcd\"\n");
+	fprintf(out, "        APPLICATION:0xXXXXXXXX  The APPLICATION block(s) whose hexadecimal big-\n");
+	fprintf(out, "                                endian representation of the 4-byte ID is\n");
+	fprintf(out, "                                \"0xXXXXXXXX\".  For the example \"abcd\" above the\n");
+	fprintf(out, "                                hexadecimal equivalalent is 0x61626364\n");
+	fprintf(out, "\n");
+	fprintf(out, "    NOTE: if both --block-number and --[except-]block-type are specified,\n");
+	fprintf(out, "          the result is the logical AND of both arguments.\n");
+	fprintf(out, "\n");
+#if 0
+	/*@@@ not implemented yet */
+	fprintf(out, "    --data-format=binary|text\n");
+	fprintf(out, "    By default a human-readable text representation of the data is displayed.\n");
+	fprintf(out, "    You may specify --data-format=binary to dump the raw binary form of each\n");
+	fprintf(out, "    metadata block.  The output can be read in using a subsequent call to\n");
+	fprintf(out, "    "metaflac --append --from-file=..."\n");
+	fprintf(out, "\n");
+#endif
+	fprintf(out, "    --application-data-format=hexdump|text\n");
+	fprintf(out, "    If the application block you are displaying contains binary data but your\n");
+	fprintf(out, "    --data-format=text, you can display a hex dump of the application data\n");
+	fprintf(out, "    contents instead using --application-data-format=hexdump\n");
+	fprintf(out, "\n");
+#if 0
+	/*@@@ not implemented yet */
+	fprintf(out, "--append\n");
+	fprintf(out, "    Insert a metadata block from a file.  The input file must be in the same\n");
+	fprintf(out, "    format as generated with --list.\n");
+	fprintf(out, "\n");
+	fprintf(out, "    --block-number=#\n");
+	fprintf(out, "    Specify the insertion point (defaults to last block).  The new block will\n");
+	fprintf(out, "    be added after the given block number.  This prevents the illegal insertion\n");
+	fprintf(out, "    of a block before the first STREAMINFO block.  You may not --append another\n");
+	fprintf(out, "    STREAMINFO block.\n");
+	fprintf(out, "\n");
+	fprintf(out, "    --from-file=filename\n");
+	fprintf(out, "    Mandatory 'option' to specify the input file containing the block contents.\n");
+	fprintf(out, "\n");
+	fprintf(out, "    --data-format=binary|text\n");
+	fprintf(out, "    By default the block contents are assumed to be in binary format.  You can\n");
+	fprintf(out, "    override this by specifying --data-format=text\n");
+	fprintf(out, "\n");
+#endif
+	fprintf(out, "--remove\n");
+	fprintf(out, "    Remove one or more metadata blocks from the metadata.  Unless\n");
+	fprintf(out, "    --dont-use-padding is specified, the blocks will be replaced with padding.\n");
+	fprintf(out, "    You may not remove the STREAMINFO block.\n");
+	fprintf(out, "\n");
+	fprintf(out, "    --block-number=#[,#[...]]\n");
+	fprintf(out, "    --block-type=type[,type[...]]\n");
+	fprintf(out, "    --except-block-type=type[,type[...]]\n");
+	fprintf(out, "    See --list above for usage.\n");
+	fprintf(out, "\n");
+	fprintf(out, "    NOTE: if both --block-number and --[except-]block-type are specified,\n");
+	fprintf(out, "          the result is the logical AND of both arguments.\n");
+	fprintf(out, "\n");
+	fprintf(out, "--remove-all\n");
+	fprintf(out, "    Remove all metadata blocks (except the STREAMINFO block) from the\n");
+	fprintf(out, "    metadata.  Unless --dont-use-padding is specified, the blocks will be\n");
+	fprintf(out, "    replaced with padding.\n");
+	fprintf(out, "\n");
+	fprintf(out, "--merge-padding\n");
+	fprintf(out, "    Merge adjacent PADDING blocks into single blocks.\n");
+	fprintf(out, "\n");
+	fprintf(out, "--sort-padding\n");
+	fprintf(out, "    Move all PADDING blocks to the end of the metadata and merge them into a\n");
+	fprintf(out, "    single block.\n");
+
+	return message? 1 : 0;
+}
diff --git a/src/metaflac/usage.h b/src/metaflac/usage.h
new file mode 100644
index 0000000..259e897
--- /dev/null
+++ b/src/metaflac/usage.h
@@ -0,0 +1,26 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef metaflac__usage_h
+#define metaflac__usage_h
+
+int short_usage(const char *message, ...);
+int long_usage(const char *message, ...);
+
+#endif
diff --git a/src/metaflac/utils.c b/src/metaflac/utils.c
new file mode 100644
index 0000000..75f42bb
--- /dev/null
+++ b/src/metaflac/utils.c
@@ -0,0 +1,276 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/safe_str.h"
+#include "share/utf8.h"
+#include "share/compat.h"
+
+void die(const char *message)
+{
+	FLAC__ASSERT(0 != message);
+	flac_fprintf(stderr, "ERROR: %s\n", message);
+	exit(1);
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+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;
+}
+#endif
+
+char *local_strdup(const char *source)
+{
+	char *ret;
+	FLAC__ASSERT(0 != source);
+	if(0 == (ret = strdup(source)))
+		die("out of memory during strdup()");
+	return ret;
+}
+
+void local_strcat(char **dest, const char *source)
+{
+	size_t ndest, nsource, outlen;
+
+	FLAC__ASSERT(0 != dest);
+	FLAC__ASSERT(0 != source);
+
+	ndest = *dest ? strlen(*dest) : 0;
+	nsource = strlen(source);
+	outlen = ndest + nsource + 1;
+
+	if(nsource == 0)
+		return;
+
+	*dest = safe_realloc_add_3op_(*dest, ndest, /*+*/nsource, /*+*/1);
+	if(*dest == NULL)
+		die("out of memory growing string");
+	safe_strncat(*dest, source, outlen);
+}
+
+static inline int local_isprint(int c)
+{
+	if (c < 32) return 0;
+	return isprint(c);
+}
+
+void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent)
+{
+	unsigned i, left = bytes;
+	const FLAC__byte *b = buf;
+
+	for(i = 0; i < bytes; i += 16) {
+		flac_printf("%s%s", filename? filename:"", filename? ":":"");
+		printf("%s%08X: "
+			"%02X %02X %02X %02X %02X %02X %02X %02X "
+			"%02X %02X %02X %02X %02X %02X %02X %02X "
+			"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
+			indent, i,
+			left >  0? (unsigned char)b[ 0] : 0,
+			left >  1? (unsigned char)b[ 1] : 0,
+			left >  2? (unsigned char)b[ 2] : 0,
+			left >  3? (unsigned char)b[ 3] : 0,
+			left >  4? (unsigned char)b[ 4] : 0,
+			left >  5? (unsigned char)b[ 5] : 0,
+			left >  6? (unsigned char)b[ 6] : 0,
+			left >  7? (unsigned char)b[ 7] : 0,
+			left >  8? (unsigned char)b[ 8] : 0,
+			left >  9? (unsigned char)b[ 9] : 0,
+			left > 10? (unsigned char)b[10] : 0,
+			left > 11? (unsigned char)b[11] : 0,
+			left > 12? (unsigned char)b[12] : 0,
+			left > 13? (unsigned char)b[13] : 0,
+			left > 14? (unsigned char)b[14] : 0,
+			left > 15? (unsigned char)b[15] : 0,
+			(left >  0) ? (local_isprint(b[ 0]) ? b[ 0] : '.') : ' ',
+			(left >  1) ? (local_isprint(b[ 1]) ? b[ 1] : '.') : ' ',
+			(left >  2) ? (local_isprint(b[ 2]) ? b[ 2] : '.') : ' ',
+			(left >  3) ? (local_isprint(b[ 3]) ? b[ 3] : '.') : ' ',
+			(left >  4) ? (local_isprint(b[ 4]) ? b[ 4] : '.') : ' ',
+			(left >  5) ? (local_isprint(b[ 5]) ? b[ 5] : '.') : ' ',
+			(left >  6) ? (local_isprint(b[ 6]) ? b[ 6] : '.') : ' ',
+			(left >  7) ? (local_isprint(b[ 7]) ? b[ 7] : '.') : ' ',
+			(left >  8) ? (local_isprint(b[ 8]) ? b[ 8] : '.') : ' ',
+			(left >  9) ? (local_isprint(b[ 9]) ? b[ 9] : '.') : ' ',
+			(left > 10) ? (local_isprint(b[10]) ? b[10] : '.') : ' ',
+			(left > 11) ? (local_isprint(b[11]) ? b[11] : '.') : ' ',
+			(left > 12) ? (local_isprint(b[12]) ? b[12] : '.') : ' ',
+			(left > 13) ? (local_isprint(b[13]) ? b[13] : '.') : ' ',
+			(left > 14) ? (local_isprint(b[14]) ? b[14] : '.') : ' ',
+			(left > 15) ? (local_isprint(b[15]) ? b[15] : '.') : ' '
+		);
+		left -= 16;
+		b += 16;
+   }
+}
+
+void print_error_with_chain_status(FLAC__Metadata_Chain *chain, const char *format, ...)
+{
+	const FLAC__Metadata_ChainStatus status = FLAC__metadata_chain_status(chain);
+	va_list args;
+
+	FLAC__ASSERT(0 != format);
+
+	va_start(args, format);
+
+	(void) flac_vfprintf(stderr, format, args);
+
+	va_end(args);
+
+	flac_fprintf(stderr, ", status = \"%s\"\n", FLAC__Metadata_ChainStatusString[status]);
+
+	if(status == FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE) {
+		flac_fprintf(stderr, "\n"
+			"The FLAC file could not be opened.  Most likely the file does not exist\n"
+			"or is not readable.\n"
+		);
+	}
+	else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE) {
+		flac_fprintf(stderr, "\n"
+			"The file does not appear to be a FLAC file.\n"
+		);
+	}
+	else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE) {
+		flac_fprintf(stderr, "\n"
+			"The FLAC file does not have write permissions.\n"
+		);
+	}
+	else if(status == FLAC__METADATA_CHAIN_STATUS_BAD_METADATA) {
+		flac_fprintf(stderr, "\n"
+			"The metadata to be written does not conform to the FLAC metadata\n"
+			"specifications.\n"
+		);
+	}
+	else if(status == FLAC__METADATA_CHAIN_STATUS_READ_ERROR) {
+		flac_fprintf(stderr, "\n"
+			"There was an error while reading the FLAC file.\n"
+		);
+	}
+	else if(status == FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR) {
+		flac_fprintf(stderr, "\n"
+			"There was an error while writing FLAC file; most probably the disk is\n"
+			"full.\n"
+		);
+	}
+	else if(status == FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR) {
+		flac_fprintf(stderr, "\n"
+			"There was an error removing the temporary FLAC file.\n"
+		);
+	}
+}
+
+FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation)
+{
+	static const char * const violations[] = {
+		"field name contains invalid character",
+		"field contains no '=' character"
+	};
+
+	char *p, *q, *s;
+
+	if(0 != field)
+		*field = local_strdup(field_ref);
+
+	s = local_strdup(field_ref);
+
+	if(0 == (p = strchr(s, '='))) {
+		free(s);
+		*violation = violations[1];
+		return false;
+	}
+	*p++ = '\0';
+
+	for(q = s; *q; q++) {
+		if(*q < 0x20 || *q > 0x7d || *q == 0x3d) {
+			free(s);
+			*violation = violations[0];
+			return false;
+		}
+	}
+
+	*name = local_strdup(s);
+	*value = local_strdup(p);
+	*length = strlen(p);
+
+	free(s);
+	return true;
+}
+
+void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__bool raw, FILE *f)
+{
+	if(0 != entry->entry) {
+		if(filename)
+			flac_fprintf(f, "%s:", filename);
+
+		if(!raw) {
+			/*
+			 * WATCHOUT: comments that contain an embedded null will
+			 * be truncated by utf_decode().
+			 */
+#ifdef _WIN32 /* if we are outputting to console, we need to use proper print functions to show unicode characters */
+			if (f == stdout || f == stderr) {
+				flac_fprintf(f, "%s", entry->entry);
+			} else {
+#endif
+			char *converted;
+
+			if(utf8_decode((const char *)entry->entry, &converted) >= 0) {
+				(void) local_fwrite(converted, 1, strlen(converted), f);
+				free(converted);
+			}
+			else {
+				(void) local_fwrite(entry->entry, 1, entry->length, f);
+			}
+#ifdef _WIN32
+			}
+#endif
+		}
+		else {
+			(void) local_fwrite(entry->entry, 1, entry->length, f);
+		}
+	}
+
+	putc('\n', f);
+}
+
+void write_vc_fields(const char *filename, const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry entry[], unsigned num_entries, FLAC__bool raw, FILE *f)
+{
+	unsigned i;
+	const unsigned field_name_length = (0 != field_name)? strlen(field_name) : 0;
+
+	for(i = 0; i < num_entries; i++) {
+		if(0 == field_name || FLAC__metadata_object_vorbiscomment_entry_matches(entry[i], field_name, field_name_length))
+			write_vc_field(filename, entry + i, raw, f);
+	}
+}
diff --git a/src/metaflac/utils.h b/src/metaflac/utils.h
new file mode 100644
index 0000000..77ee13c
--- /dev/null
+++ b/src/metaflac/utils.h
@@ -0,0 +1,42 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef metaflac__utils_h
+#define metaflac__utils_h
+
+#include "FLAC/metadata.h"
+#include <stdio.h> /* for FILE */
+
+void die(const char *message);
+#ifdef FLAC__VALGRIND_TESTING
+size_t local_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
+#else
+#define local_fwrite fwrite
+#endif
+char *local_strdup(const char *source);
+void local_strcat(char **dest, const char *source);
+void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent);
+void print_error_with_chain_status(FLAC__Metadata_Chain *chain, const char *format, ...);
+
+FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation);
+
+void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__bool raw, FILE *f);
+void write_vc_fields(const char *filename, const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry entry[], unsigned num_entries, FLAC__bool raw, FILE *f);
+
+#endif
diff --git a/src/plugin_common/CMakeLists.txt b/src/plugin_common/CMakeLists.txt
new file mode 100644
index 0000000..e5e6d84
--- /dev/null
+++ b/src/plugin_common/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.12)
+
+add_library(plugin_common STATIC
+    charset.c
+    dither.c
+    replaygain.c
+    tags.c)
+target_link_libraries(plugin_common PUBLIC $<TARGET_NAME_IF_EXISTS:Iconv::Iconv>)
diff --git a/src/plugin_common/Makefile.am b/src/plugin_common/Makefile.am
new file mode 100644
index 0000000..2c41f5b
--- /dev/null
+++ b/src/plugin_common/Makefile.am
@@ -0,0 +1,40 @@
+#  plugin_common - Routines common to several plugins
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libplugin_common.la
+
+noinst_HEADERS = \
+	all.h \
+	charset.h \
+	defs.h \
+	dither.h \
+	replaygain.h \
+	tags.h
+
+libplugin_common_la_SOURCES = \
+	charset.c \
+	dither.c \
+	replaygain.c \
+	tags.c
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	README
diff --git a/src/plugin_common/Makefile.lite b/src/plugin_common/Makefile.lite
new file mode 100644
index 0000000..dc494a7
--- /dev/null
+++ b/src/plugin_common/Makefile.lite
@@ -0,0 +1,42 @@
+#  plugin_common - Routines common to several plugins
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+LIB_NAME = libplugin_common
+INCLUDES = -I$(topdir)/include -I$(HOME)/local/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lgrabbag -lreplaygain_analysis -lFLAC $(OGG_LIBS) -lm
+endif
+
+SRCS_C = \
+	charset.c \
+	dither.c \
+	replaygain.c \
+	tags.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/plugin_common/README b/src/plugin_common/README
new file mode 100644
index 0000000..5a33526
--- /dev/null
+++ b/src/plugin_common/README
@@ -0,0 +1,2 @@
+This directory contains a convenience library of routines that are
+common to the plugins.
diff --git a/src/plugin_common/all.h b/src/plugin_common/all.h
new file mode 100644
index 0000000..1639ac9
--- /dev/null
+++ b/src/plugin_common/all.h
@@ -0,0 +1,27 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__ALL_H
+#define FLAC__PLUGIN_COMMON__ALL_H
+
+#include "charset.h"
+#include "dither.h"
+#include "tags.h"
+
+#endif
diff --git a/src/plugin_common/charset.c b/src/plugin_common/charset.c
new file mode 100644
index 0000000..85e574b
--- /dev/null
+++ b/src/plugin_common/charset.c
@@ -0,0 +1,158 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Only slightly modified charset.c from:
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  Håvard Kvålen <havardk@xmms.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "charset.h"
+
+
+/*************
+ * Functions *
+ *************/
+
+char* FLAC_plugin__charset_get_current (void)
+{
+	char *charset = getenv("CHARSET");
+
+#ifdef HAVE_LANGINFO_CODESET
+	if (!charset)
+		charset = nl_langinfo(CODESET);
+#endif
+	if (!charset)
+		charset = "ISO-8859-1";
+
+	return charset;
+}
+
+
+#ifdef HAVE_ICONV
+char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
+{
+	size_t outleft, outsize, length;
+	iconv_t cd;
+	char *out, *outptr;
+	const char *input = string;
+
+	if (!string)
+		return NULL;
+
+	length = strlen(string);
+
+	if ((cd = iconv_open(to, from)) == (iconv_t)-1)
+	{
+#ifndef NDEBUG
+		fprintf(stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to);
+#endif
+		return strdup(string);
+	}
+
+	/* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */
+	/* + 1 for nul in case len == 1 */
+	outsize = ((length + 3) & ~3) + 1;
+	if(outsize < length) /* overflow check */
+		return NULL;
+	out = malloc(outsize);
+	outleft = outsize - 1;
+	outptr = out;
+
+retry:
+	if (iconv(cd, (char**)&input, &length, &outptr, &outleft) == (size_t)(-1))
+	{
+		int used;
+		switch (errno)
+		{
+			case E2BIG:
+				used = outptr - out;
+				if((outsize - 1) * 2 + 1 <= outsize) { /* overflow check */
+					free(out);
+					return NULL;
+				}
+				outsize = (outsize - 1) * 2 + 1;
+				out = realloc(out, outsize);
+				outptr = out + used;
+				outleft = outsize - 1 - used;
+				goto retry;
+			case EINVAL:
+				break;
+			case EILSEQ:
+				/* Invalid sequence, try to get the rest of the string */
+				input++;
+				length = strlen(input);
+				goto retry;
+			default:
+#ifndef NDEBUG
+				fprintf(stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno));
+#endif
+				break;
+		}
+	}
+	*outptr = '\0';
+
+	iconv_close(cd);
+	return out;
+}
+#else
+char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
+{
+	(void)from, (void)to;
+	if (!string)
+		return NULL;
+	return strdup(string);
+}
+#endif
+
+#ifdef HAVE_ICONV
+int FLAC_plugin__charset_test_conversion (char *from, char *to)
+{
+	iconv_t cd;
+
+	if ((cd=iconv_open(to,from)) == (iconv_t)-1)
+	{
+		/* Conversion not supported */
+		return 0;
+	}
+	iconv_close(cd);
+	return 1;
+}
+#else
+int FLAC_plugin__charset_test_conversion (char *from, char *to)
+{
+	(void)from, (void)to;
+	return 1;
+}
+#endif
diff --git a/src/plugin_common/charset.h b/src/plugin_common/charset.h
new file mode 100644
index 0000000..d4a62ce
--- /dev/null
+++ b/src/plugin_common/charset.h
@@ -0,0 +1,40 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Only slightly modified charset.h from:
+ * charset.h - 2001/12/04
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+
+#ifndef FLAC__PLUGIN_COMMON__CHARSET_H
+#define FLAC__PLUGIN_COMMON__CHARSET_H
+
+
+/**************
+ * Prototypes *
+ **************/
+
+char *FLAC_plugin__charset_get_current(void);
+char *FLAC_plugin__charset_convert_string(const char *string, char *from, char *to);
+
+/* returns 1 for success, 0 for failure or no iconv */
+int FLAC_plugin__charset_test_conversion(char *from, char *to);
+
+#endif
diff --git a/src/plugin_common/defs.h b/src/plugin_common/defs.h
new file mode 100644
index 0000000..61896ae
--- /dev/null
+++ b/src/plugin_common/defs.h
@@ -0,0 +1,25 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__DEFS_H
+#define FLAC__PLUGIN_COMMON__DEFS_H
+
+#define FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS 2
+
+#endif
diff --git a/src/plugin_common/dither.c b/src/plugin_common/dither.c
new file mode 100644
index 0000000..b4c9b67
--- /dev/null
+++ b/src/plugin_common/dither.c
@@ -0,0 +1,263 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * dithering routine derived from (other GPLed source):
+ * mad - MPEG audio decoder
+ * Copyright (C) 2000-2001 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "dither.h"
+#include "FLAC/assert.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+
+/* 32-bit pseudo-random number generator
+ *
+ * @@@ According to Miroslav, this one is poor quality, the one from the
+ * @@@ original replaygain code is much better
+ */
+static FLaC__INLINE FLAC__uint32 prng(FLAC__uint32 state)
+{
+	return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
+}
+
+/* dither routine derived from MAD winamp plugin */
+
+typedef struct {
+	FLAC__int32 error[3];
+	FLAC__int32 random;
+} dither_state;
+
+static FLAC__int32 linear_dither(uint32_t source_bps, uint32_t target_bps, FLAC__int32 sample, dither_state *dither, const FLAC__int32 MIN, const FLAC__int32 MAX)
+{
+	uint32_t scalebits;
+	FLAC__int32 output, mask, random;
+
+	FLAC__ASSERT(source_bps < 32);
+	FLAC__ASSERT(target_bps <= 24);
+	FLAC__ASSERT(target_bps <= source_bps);
+
+	/* noise shape */
+	sample += dither->error[0] - dither->error[1] + dither->error[2];
+
+	dither->error[2] = dither->error[1];
+	dither->error[1] = dither->error[0] / 2;
+
+	/* bias */
+	output = sample + (1L << (source_bps - target_bps - 1));
+
+	scalebits = source_bps - target_bps;
+	mask = (1L << scalebits) - 1;
+
+	/* dither */
+	random = (FLAC__int32)prng(dither->random);
+	output += (random & mask) - (dither->random & mask);
+
+	dither->random = random;
+
+	/* clip */
+	if(output > MAX) {
+		output = MAX;
+
+		if(sample > MAX)
+			sample = MAX;
+	}
+	else if(output < MIN) {
+		output = MIN;
+
+		if(sample < MIN)
+			sample = MIN;
+	}
+
+	/* quantize */
+	output &= ~mask;
+
+	/* error feedback */
+	dither->error[0] = sample - output;
+
+	/* scale */
+	return output >> scalebits;
+}
+
+size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, uint32_t source_bps, uint32_t target_bps)
+{
+	static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
+	FLAC__byte * const start = data;
+	FLAC__int32 sample;
+	const FLAC__int32 *input_;
+	uint32_t samples, channel;
+	const uint32_t bytes_per_sample = target_bps / 8;
+	const uint32_t incr = bytes_per_sample * channels;
+
+	FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS);
+	FLAC__ASSERT(source_bps < 32);
+	FLAC__ASSERT(target_bps <= 24);
+	FLAC__ASSERT(target_bps <= source_bps);
+	FLAC__ASSERT((source_bps & 7) == 0);
+	FLAC__ASSERT((target_bps & 7) == 0);
+
+	if(source_bps != target_bps) {
+		const FLAC__int32 MIN = -(1L << (source_bps - 1));
+		const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */
+
+		for(channel = 0; channel < channels; channel++) {
+
+			samples = wide_samples;
+			data = start + bytes_per_sample * channel;
+			input_ = input[channel];
+
+			while(samples--) {
+				sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX);
+
+				switch(target_bps) {
+					case 8:
+						data[0] = sample ^ 0x80;
+						break;
+					case 16:
+						data[0] = (FLAC__byte)(sample >> 8);
+						data[1] = (FLAC__byte)sample;
+						break;
+					case 24:
+						data[0] = (FLAC__byte)(sample >> 16);
+						data[1] = (FLAC__byte)(sample >> 8);
+						data[2] = (FLAC__byte)sample;
+						break;
+				}
+
+				data += incr;
+			}
+		}
+	}
+	else {
+		for(channel = 0; channel < channels; channel++) {
+			samples = wide_samples;
+			data = start + bytes_per_sample * channel;
+			input_ = input[channel];
+
+			while(samples--) {
+				sample = *input_++;
+
+				switch(target_bps) {
+					case 8:
+						data[0] = sample ^ 0x80;
+						break;
+					case 16:
+						data[0] = (FLAC__byte)(sample >> 8);
+						data[1] = (FLAC__byte)sample;
+						break;
+					case 24:
+						data[0] = (FLAC__byte)(sample >> 16);
+						data[1] = (FLAC__byte)(sample >> 8);
+						data[2] = (FLAC__byte)sample;
+						break;
+				}
+
+				data += incr;
+			}
+		}
+	}
+
+	return wide_samples * channels * (target_bps/8);
+}
+
+size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, uint32_t source_bps, uint32_t target_bps)
+{
+	static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
+	FLAC__byte * const start = data;
+	FLAC__int32 sample;
+	const FLAC__int32 *input_;
+	uint32_t samples, channel;
+	const uint32_t bytes_per_sample = target_bps / 8;
+	const uint32_t incr = bytes_per_sample * channels;
+
+	FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS);
+	FLAC__ASSERT(source_bps < 32);
+	FLAC__ASSERT(target_bps <= 24);
+	FLAC__ASSERT(target_bps <= source_bps);
+	FLAC__ASSERT((source_bps & 7) == 0);
+	FLAC__ASSERT((target_bps & 7) == 0);
+
+	if(source_bps != target_bps) {
+		const FLAC__int32 MIN = -(1L << (source_bps - 1));
+		const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */
+
+		for(channel = 0; channel < channels; channel++) {
+
+			samples = wide_samples;
+			data = start + bytes_per_sample * channel;
+			input_ = input[channel];
+
+			while(samples--) {
+				sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX);
+
+				switch(target_bps) {
+					case 8:
+						data[0] = sample ^ 0x80;
+						break;
+					case 24:
+						data[2] = (FLAC__byte)(sample >> 16);
+						/* fall through */
+					case 16:
+						data[1] = (FLAC__byte)(sample >> 8);
+						data[0] = (FLAC__byte)sample;
+				}
+
+				data += incr;
+			}
+		}
+	}
+	else {
+		for(channel = 0; channel < channels; channel++) {
+			samples = wide_samples;
+			data = start + bytes_per_sample * channel;
+			input_ = input[channel];
+
+			while(samples--) {
+				sample = *input_++;
+
+				switch(target_bps) {
+					case 8:
+						data[0] = sample ^ 0x80;
+						break;
+					case 24:
+						data[2] = (FLAC__byte)(sample >> 16);
+						/* fall through */
+					case 16:
+						data[1] = (FLAC__byte)(sample >> 8);
+						data[0] = (FLAC__byte)sample;
+				}
+
+				data += incr;
+			}
+		}
+	}
+
+	return wide_samples * channels * (target_bps/8);
+}
diff --git a/src/plugin_common/dither.h b/src/plugin_common/dither.h
new file mode 100644
index 0000000..e7c1301
--- /dev/null
+++ b/src/plugin_common/dither.h
@@ -0,0 +1,30 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__DITHER_H
+#define FLAC__PLUGIN_COMMON__DITHER_H
+
+#include <stdlib.h> /* for size_t */
+#include "defs.h" /* buy FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS for the caller */
+#include "FLAC/ordinals.h"
+
+size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, uint32_t source_bps, uint32_t target_bps);
+size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, uint32_t source_bps, uint32_t target_bps);
+
+#endif
diff --git a/src/plugin_common/replaygain.c b/src/plugin_common/replaygain.c
new file mode 100644
index 0000000..40fb0fc
--- /dev/null
+++ b/src/plugin_common/replaygain.c
@@ -0,0 +1,65 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ * Copyright (C) 2003  Philip Jägenstedt
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "replaygain.h"
+#include "FLAC/ordinals.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+
+FLAC__bool FLAC_plugin__replaygain_get_from_file(const char *filename,
+                                                 double *reference, FLAC__bool *reference_set,
+                                                 double *track_gain, FLAC__bool *track_gain_set,
+                                                 double *album_gain, FLAC__bool *album_gain_set,
+                                                 double *track_peak, FLAC__bool *track_peak_set,
+                                                 double *album_peak, FLAC__bool *album_peak_set)
+{
+	FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
+	FLAC__bool ret = false;
+
+	*track_gain_set = *album_gain_set = *track_peak_set = *album_peak_set = false;
+
+	if(0 != iterator) {
+		if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+			FLAC__bool got_vorbis_comments = false;
+			ret = true;
+			do {
+				if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+					FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
+					if(0 != block) {
+						if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/false, /*strict=*/true, reference, track_gain, track_peak)) {
+							*reference_set = *track_gain_set = *track_peak_set = true;
+						}
+						if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/true, /*strict=*/true, reference, album_gain, album_peak)) {
+							*reference_set = *album_gain_set = *album_peak_set = true;
+						}
+						FLAC__metadata_object_delete(block);
+						got_vorbis_comments = true;
+					}
+				}
+			} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
+		}
+		FLAC__metadata_simple_iterator_delete(iterator);
+	}
+	return ret;
+}
diff --git a/src/plugin_common/replaygain.h b/src/plugin_common/replaygain.h
new file mode 100644
index 0000000..dcb2aa9
--- /dev/null
+++ b/src/plugin_common/replaygain.h
@@ -0,0 +1,33 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ * Copyright (C) 2003  Philip Jägenstedt
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__REPLAYGAIN_H
+#define FLAC__PLUGIN_COMMON__REPLAYGAIN_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool FLAC_plugin__replaygain_get_from_file(const char *filename,
+                                           double *reference, FLAC__bool *reference_set,
+                                           double *track_gain, FLAC__bool *track_gain_set,
+                                           double *album_gain, FLAC__bool *album_gain_set,
+                                           double *track_peak, FLAC__bool *track_peak_set,
+                                           double *album_peak, FLAC__bool *album_peak_set);
+
+#endif
diff --git a/src/plugin_common/tags.c b/src/plugin_common/tags.c
new file mode 100644
index 0000000..ae440c5
--- /dev/null
+++ b/src/plugin_common/tags.c
@@ -0,0 +1,359 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tags.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/alloc.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+
+static FLaC__INLINE size_t local__wide_strlen(const FLAC__uint16 *s)
+{
+	size_t n = 0;
+	while(*s++)
+		n++;
+	return n;
+}
+
+/*
+ * 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 size_t local__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;
+	}
+}
+
+
+static size_t local__utf8_to_ucs2(const FLAC__byte *utf8, FLAC__uint16 *ucs2)
+{
+	const size_t len = local__utf8len(utf8);
+
+	FLAC__ASSERT(0 != ucs2);
+
+	if (len == 1)
+		*ucs2 = *utf8;
+	else if (len == 2)
+		*ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F);
+	else if (len == 3)
+		*ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F);
+	else
+		*ucs2 = '?';
+
+	return len;
+}
+
+static FLAC__uint16 *local__convert_utf8_to_ucs2(const char *src, uint32_t length)
+{
+	FLAC__uint16 *out;
+	size_t chars = 0;
+
+	FLAC__ASSERT(0 != src);
+
+	/* calculate length */
+	{
+		const uint8_t *s, *end;
+		for (s=(const uint8_t *)src, end=s+length; s<end; chars++) {
+			const uint32_t n = local__utf8len(s);
+			if (n == 0)
+				return 0;
+			s += n;
+		}
+		FLAC__ASSERT(s == end);
+	}
+
+	/* allocate */
+	out = safe_malloc_mul_2op_(chars, /*times*/sizeof(FLAC__uint16));
+	if (0 == out) {
+		FLAC__ASSERT(0);
+		return 0;
+	}
+
+	/* convert */
+	{
+		const uint8_t *s = (const uint8_t *)src;
+		FLAC__uint16 *u = out;
+		for ( ; chars; chars--)
+			s += local__utf8_to_ucs2(s, u++);
+	}
+
+	return out;
+}
+
+static FLaC__INLINE size_t local__ucs2len(FLAC__uint16 ucs2)
+{
+	if (ucs2 < 0x0080)
+		return 1;
+	else if (ucs2 < 0x0800)
+		return 2;
+	else
+		return 3;
+}
+
+static size_t local__ucs2_to_utf8(FLAC__uint16 ucs2, FLAC__byte *utf8)
+{
+	if (ucs2 < 0x080) {
+		utf8[0] = (FLAC__byte)ucs2;
+		return 1;
+	}
+	else if (ucs2 < 0x800) {
+		utf8[0] = 0xc0 | (ucs2 >> 6);
+		utf8[1] = 0x80 | (ucs2 & 0x3f);
+		return 2;
+	}
+	else {
+		utf8[0] = 0xe0 | (ucs2 >> 12);
+		utf8[1] = 0x80 | ((ucs2 >> 6) & 0x3f);
+		utf8[2] = 0x80 | (ucs2 & 0x3f);
+		return 3;
+	}
+}
+
+static char *local__convert_ucs2_to_utf8(const FLAC__uint16 *src, uint32_t length)
+{
+	char *out;
+	size_t len = 0, n;
+
+	FLAC__ASSERT(0 != src);
+
+	/* calculate length */
+	{
+		uint32_t i;
+		for (i = 0; i < length; i++) {
+			n = local__ucs2len(src[i]);
+			if(len + n < len) /* overflow check */
+				return 0;
+			len += n;
+		}
+	}
+
+	/* allocate */
+	out = safe_malloc_mul_2op_(len, /*times*/sizeof(char));
+	if (0 == out)
+		return 0;
+
+	/* convert */
+	{
+		uint8_t *u = (uint8_t *)out;
+		for ( ; *src; src++)
+			u += local__ucs2_to_utf8(*src, u);
+		local__ucs2_to_utf8(*src, u);
+	}
+
+	return out;
+}
+
+
+FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags)
+{
+	if(!FLAC__metadata_get_tags(filename, tags))
+		if(0 == (*tags = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)))
+			return false;
+	return true;
+}
+
+FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__Metadata_Iterator *iterator;
+	FLAC__StreamMetadata *block;
+	FLAC__bool got_vorbis_comments = false;
+	FLAC__bool ok;
+
+	if(0 == (chain = FLAC__metadata_chain_new()))
+		return false;
+
+	if(!FLAC__metadata_chain_read(chain, filename)) {
+		FLAC__metadata_chain_delete(chain);
+		return false;
+	}
+
+	if(0 == (iterator = FLAC__metadata_iterator_new())) {
+		FLAC__metadata_chain_delete(chain);
+		return false;
+	}
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	do {
+		if(FLAC__metadata_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+			got_vorbis_comments = true;
+	} while(!got_vorbis_comments && FLAC__metadata_iterator_next(iterator));
+
+	if(0 == (block = FLAC__metadata_object_clone(tags))) {
+		FLAC__metadata_chain_delete(chain);
+		FLAC__metadata_iterator_delete(iterator);
+		return false;
+	}
+
+	if(got_vorbis_comments)
+		ok = FLAC__metadata_iterator_set_block(iterator, block);
+	else
+		ok = FLAC__metadata_iterator_insert_block_after(iterator, block);
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	if(ok) {
+		FLAC__metadata_chain_sort_padding(chain);
+		ok = FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/true);
+	}
+
+	FLAC__metadata_chain_delete(chain);
+
+	return ok;
+}
+
+void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags)
+{
+	FLAC__metadata_object_delete(*tags);
+	*tags = 0;
+}
+
+const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name)
+{
+	const int i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name);
+	return (i < 0? 0 : strchr((const char *)tags->data.vorbis_comment.comments[i].entry, '=')+1);
+}
+
+FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name)
+{
+	const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name);
+	if(0 == utf8)
+		return 0;
+	return local__convert_utf8_to_ucs2(utf8, strlen(utf8)+1); /* +1 for terminating null */
+}
+
+int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name)
+{
+	return FLAC__metadata_object_vorbiscomment_remove_entries_matching(tags, name);
+}
+
+int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags)
+{
+	int n = (int)tags->data.vorbis_comment.num_comments;
+	if(n > 0) {
+		if(!FLAC__metadata_object_vorbiscomment_resize_comments(tags, 0))
+			n = -1;
+	}
+	return n;
+}
+
+FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator)
+{
+	int i;
+
+	FLAC__ASSERT(0 != tags);
+	FLAC__ASSERT(0 != name);
+	FLAC__ASSERT(0 != value);
+
+	if(separator && (i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name)) >= 0) {
+		FLAC__StreamMetadata_VorbisComment_Entry *entry = tags->data.vorbis_comment.comments+i;
+		const size_t value_len = strlen(value);
+		const size_t separator_len = strlen(separator);
+		FLAC__byte *new_entry;
+		if(0 == (new_entry = safe_realloc_add_4op_(entry->entry, entry->length, /*+*/value_len, /*+*/separator_len, /*+*/1)))
+			return false;
+		memcpy(new_entry+entry->length, separator, separator_len);
+		entry->length += separator_len;
+		memcpy(new_entry+entry->length, value, value_len);
+		entry->length += value_len;
+		new_entry[entry->length] = '\0';
+		entry->entry = new_entry;
+	}
+	else {
+		FLAC__StreamMetadata_VorbisComment_Entry entry;
+		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, value))
+			return false;
+		FLAC__metadata_object_vorbiscomment_append_comment(tags, entry, /*copy=*/false);
+	}
+	return true;
+}
+
+FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all)
+{
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+
+	FLAC__ASSERT(0 != tags);
+	FLAC__ASSERT(0 != name);
+	FLAC__ASSERT(0 != value);
+
+	{
+		char *utf8 = local__convert_ucs2_to_utf8(value, local__wide_strlen(value)+1); /* +1 for the terminating null */
+		if(0 == utf8)
+			return false;
+		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, utf8)) {
+			free(utf8);
+			return false;
+		}
+		free(utf8);
+	}
+	if(!FLAC__metadata_object_vorbiscomment_replace_comment(tags, entry, replace_all, /*copy=*/false))
+		return false;
+	return true;
+}
diff --git a/src/plugin_common/tags.h b/src/plugin_common/tags.h
new file mode 100644
index 0000000..8b45367
--- /dev/null
+++ b/src/plugin_common/tags.h
@@ -0,0 +1,75 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__TAGS_H
+#define FLAC__PLUGIN_COMMON__TAGS_H
+
+#include "FLAC/format.h"
+
+FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags);
+FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags);
+
+/*
+ * Deletes the tags object and sets '*tags' to NULL.
+ */
+void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags);
+
+/*
+ * Gets the value (in UTF-8) of the first tag with the given name (NULL if no
+ * such tag exists).
+ */
+const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Gets the value (in UCS-2) of the first tag with the given name (NULL if no
+ * such tag exists).
+ *
+ * NOTE: the returned string is malloc()ed and must be free()d by the caller.
+ */
+FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Removes all tags with the given 'name'.  Returns the number of tags removed,
+ * or -1 on memory allocation error.
+ */
+int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Removes all tags.  Returns the number of tags removed, or -1 on memory
+ * allocation error.
+ */
+int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags);
+
+/*
+ * Adds a "name=value" tag to the tags.  'value' must be in UTF-8.  If
+ * 'separator' is non-NULL and 'tags' already contains a tag for 'name', the
+ * first such tag's value is appended with separator, then value.
+ */
+FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator);
+
+/*
+ * Adds a "name=value" tag to the tags.  'value' must be in UCS-2.  If 'tags'
+ * already contains a tag or tags for 'name', then they will be replaced
+ * according to 'replace_all': if 'replace_all' is false, only the first such
+ * tag will be replaced; if true, all matching tags will be replaced by the one
+ * new tag.
+ */
+FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all);
+
+#endif
diff --git a/src/plugin_xmms/CMakeLists.txt b/src/plugin_xmms/CMakeLists.txt
new file mode 100644
index 0000000..3c4b716
--- /dev/null
+++ b/src/plugin_xmms/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(xmms-flac STATIC
+    charset.c
+    configure.c
+    fileinfo.c
+    http.c
+    plugin.c
+    tag.c)
+target_link_libraries(xmms-flac plugin_common)
diff --git a/src/plugin_xmms/Makefile.am b/src/plugin_xmms/Makefile.am
new file mode 100644
index 0000000..3d011a3
--- /dev/null
+++ b/src/plugin_xmms/Makefile.am
@@ -0,0 +1,67 @@
+#  libxmms-flac - XMMS FLAC input plugin
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite
+
+noinst_HEADERS = \
+	charset.h \
+	configure.h \
+	http.h \
+	locale_hack.h \
+	plugin.h \
+	tag.h
+
+AM_CFLAGS = @OGG_CFLAGS@ @XMMS_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src
+if FLaC__INSTALL_XMMS_PLUGIN_LOCALLY
+xmmsinputplugindir = $(HOME)/.xmms/Plugins
+else
+xmmsinputplugindir = @XMMS_INPUT_PLUGIN_DIR@
+endif
+
+xmmsinputplugin_LTLIBRARIES = libxmms-flac.la
+
+plugin_sources = charset.c configure.c fileinfo.c http.c plugin.c tag.c
+
+libxmms_flac_la_SOURCES = $(plugin_sources)
+
+# work around the bug in libtool where its relinking fails with a different DESTDIR
+# for libtool bug info see:
+#   http://mail.gnu.org/pipermail/bug-libtool/2002-February/003018.html
+#   http://mail.gnu.org/pipermail/libtool/2002-April/006244.html
+#   http://mail.gnu.org/pipermail/libtool/2002-April/006250.html
+# for fix info see:
+#   http://lists.freshrpms.net/pipermail/rpm-list/2002-April/000746.html
+# the workaround is the extra '-L$(top_builddir)/src/libFLAC/.libs'
+libxmms_flac_la_LIBADD = \
+	$(top_builddir)/src/plugin_common/libplugin_common.la \
+	$(top_builddir)/src/share/grabbag/libgrabbag.la \
+	$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+	$(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
+	$(top_builddir)/src/share/utf8/libutf8.la \
+	$(top_builddir)/src/libFLAC/libFLAC.la \
+	-L$(top_builddir)/src/libFLAC/.libs \
+	@XMMS_LIBS@ \
+	@LIBICONV@
+libxmms_flac_la_LDFLAGS = -module -avoid-version
diff --git a/src/plugin_xmms/Makefile.lite b/src/plugin_xmms/Makefile.lite
new file mode 100644
index 0000000..87f081e
--- /dev/null
+++ b/src/plugin_xmms/Makefile.lite
@@ -0,0 +1,45 @@
+#  libxmms-flac - XMMS FLAC input plugin
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+LIB_NAME  = libxmms-flac
+INCLUDES  = -I./include -I$(topdir)/include -I.. $(shell xmms-config --cflags)
+# refer to the static libs explicitly
+ifeq ($(OS),Darwin)
+    LIBS = $(libdir)/libFLAC.a $(libdir)/libplugin_common.a $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libreplaygain_synthesis.a $(OGG_EXPLICIT_LIBS) $(ICONV_LIBS) -lm -lstdc++ -lz
+else
+    LIBS = $(libdir)/libFLAC.a $(libdir)/libplugin_common.a $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libreplaygain_synthesis.a $(OGG_LIBS) -lm -lsupc++ -lz
+endif
+
+SRCS_C = \
+	charset.c \
+	configure.c \
+	plugin.c \
+	fileinfo.c \
+	http.c \
+	tag.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/plugin_xmms/charset.c b/src/plugin_xmms/charset.c
new file mode 100644
index 0000000..6d86848
--- /dev/null
+++ b/src/plugin_xmms/charset.c
@@ -0,0 +1,200 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Daisuke Shimamura
+ *
+ * Almost from charset.c
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  Håvard Kvålen <havardk@xmms.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "plugin_common/charset.h"
+#include "charset.h"
+#include "configure.h"
+#include "locale_hack.h"
+
+
+/****************
+ * Declarations *
+ ****************/
+
+#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) )
+const CharsetInfo charset_trans_array[] = {
+	{N_("Arabic (IBM-864)"),                  "IBM864"        },
+	{N_("Arabic (ISO-8859-6)"),               "ISO-8859-6"    },
+	{N_("Arabic (Windows-1256)"),             "windows-1256"  },
+	{N_("Baltic (ISO-8859-13)"),              "ISO-8859-13"   },
+	{N_("Baltic (ISO-8859-4)"),               "ISO-8859-4"    },
+	{N_("Baltic (Windows-1257)"),             "windows-1257"  },
+	{N_("Celtic (ISO-8859-14)"),              "ISO-8859-14"   },
+	{N_("Central European (IBM-852)"),        "IBM852"        },
+	{N_("Central European (ISO-8859-2)"),     "ISO-8859-2"    },
+	{N_("Central European (Windows-1250)"),   "windows-1250"  },
+	{N_("Chinese Simplified (GB18030)"),      "gb18030"       },
+	{N_("Chinese Simplified (GB2312)"),       "GB2312"        },
+	{N_("Chinese Traditional (Big5)"),        "Big5"          },
+	{N_("Chinese Traditional (Big5-HKSCS)"),  "Big5-HKSCS"    },
+	{N_("Cyrillic (IBM-855)"),                "IBM855"        },
+	{N_("Cyrillic (ISO-8859-5)"),             "ISO-8859-5"    },
+	{N_("Cyrillic (ISO-IR-111)"),             "ISO-IR-111"    },
+	{N_("Cyrillic (KOI8-R)"),                 "KOI8-R"        },
+	{N_("Cyrillic (Windows-1251)"),           "windows-1251"  },
+	{N_("Cyrillic/Russian (CP-866)"),         "IBM866"        },
+	{N_("Cyrillic/Ukrainian (KOI8-U)"),       "KOI8-U"        },
+	{N_("English (US-ASCII)"),                "us-ascii"      },
+	{N_("Greek (ISO-8859-7)"),                "ISO-8859-7"    },
+	{N_("Greek (Windows-1253)"),              "windows-1253"  },
+	{N_("Hebrew (IBM-862)"),                  "IBM862"        },
+	{N_("Hebrew (Windows-1255)"),             "windows-1255"  },
+	{N_("Japanese (EUC-JP)"),                 "EUC-JP"        },
+	{N_("Japanese (ISO-2022-JP)"),            "ISO-2022-JP"   },
+	{N_("Japanese (Shift_JIS)"),              "Shift_JIS"     },
+	{N_("Korean (EUC-KR)"),                   "EUC-KR"        },
+	{N_("Nordic (ISO-8859-10)"),              "ISO-8859-10"   },
+	{N_("South European (ISO-8859-3)"),       "ISO-8859-3"    },
+	{N_("Thai (TIS-620)"),                    "TIS-620"       },
+	{N_("Turkish (IBM-857)"),                 "IBM857"        },
+	{N_("Turkish (ISO-8859-9)"),              "ISO-8859-9"    },
+	{N_("Turkish (Windows-1254)"),            "windows-1254"  },
+	{N_("Unicode (UTF-7)"),                   "UTF-7"         },
+	{N_("Unicode (UTF-8)"),                   "UTF-8"         },
+	{N_("Unicode (UTF-16BE)"),                "UTF-16BE"      },
+	{N_("Unicode (UTF-16LE)"),                "UTF-16LE"      },
+	{N_("Unicode (UTF-32BE)"),                "UTF-32BE"      },
+	{N_("Unicode (UTF-32LE)"),                "UTF-32LE"      },
+	{N_("Vietnamese (VISCII)"),               "VISCII"        },
+	{N_("Vietnamese (Windows-1258)"),         "windows-1258"  },
+	{N_("Visual Hebrew (ISO-8859-8)"),        "ISO-8859-8"    },
+	{N_("Western (IBM-850)"),                 "IBM850"        },
+	{N_("Western (ISO-8859-1)"),              "ISO-8859-1"    },
+	{N_("Western (ISO-8859-15)"),             "ISO-8859-15"   },
+	{N_("Western (Windows-1252)"),            "windows-1252"  }
+
+	/*
+	 * From this point, character sets aren't supported by iconv
+	 */
+#if 0
+	{N_("Arabic (IBM-864-I)"),                "IBM864i"              },
+	{N_("Arabic (ISO-8859-6-E)"),             "ISO-8859-6-E"         },
+	{N_("Arabic (ISO-8859-6-I)"),             "ISO-8859-6-I"         },
+	{N_("Arabic (MacArabic)"),                "x-mac-arabic"         },
+	{N_("Armenian (ARMSCII-8)"),              "armscii-8"            },
+	{N_("Central European (MacCE)"),          "x-mac-ce"             },
+	{N_("Chinese Simplified (GBK)"),          "x-gbk"                },
+	{N_("Chinese Simplified (HZ)"),           "HZ-GB-2312"           },
+	{N_("Chinese Traditional (EUC-TW)"),      "x-euc-tw"             },
+	{N_("Croatian (MacCroatian)"),            "x-mac-croatian"       },
+	{N_("Cyrillic (MacCyrillic)"),            "x-mac-cyrillic"       },
+	{N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian"      },
+	{N_("Farsi (MacFarsi)"),                  "x-mac-farsi"},
+	{N_("Greek (MacGreek)"),                  "x-mac-greek"          },
+	{N_("Gujarati (MacGujarati)"),            "x-mac-gujarati"       },
+	{N_("Gurmukhi (MacGurmukhi)"),            "x-mac-gurmukhi"       },
+	{N_("Hebrew (ISO-8859-8-E)"),             "ISO-8859-8-E"         },
+	{N_("Hebrew (ISO-8859-8-I)"),             "ISO-8859-8-I"         },
+	{N_("Hebrew (MacHebrew)"),                "x-mac-hebrew"         },
+	{N_("Hindi (MacDevanagari)"),             "x-mac-devanagari"     },
+	{N_("Icelandic (MacIcelandic)"),          "x-mac-icelandic"      },
+	{N_("Korean (JOHAB)"),                    "x-johab"              },
+	{N_("Korean (UHC)"),                      "x-windows-949"        },
+	{N_("Romanian (MacRomanian)"),            "x-mac-romanian"       },
+	{N_("Turkish (MacTurkish)"),              "x-mac-turkish"        },
+	{N_("User Defined"),                      "x-user-defined"       },
+	{N_("Vietnamese (TCVN)"),                 "x-viet-tcvn5712"      },
+	{N_("Vietnamese (VPS)"),                  "x-viet-vps"           },
+	{N_("Western (MacRoman)"),                "x-mac-roman"          },
+	/* charsets whithout posibly translatable names */
+	{"T61.8bit",                              "T61.8bit"             },
+	{"x-imap4-modified-utf7",                 "x-imap4-modified-utf7"},
+	{"x-u-escaped",                           "x-u-escaped"          },
+	{"windows-936",                           "windows-936"          }
+#endif
+};
+
+/*************
+ * Functions *
+ *************/
+
+/*
+ * Commons conversion functions
+ */
+char *convert_from_utf8_to_user(const char *string)
+{
+	return FLAC_plugin__charset_convert_string(string, "UTF-8", flac_cfg.title.user_char_set);
+}
+
+char *convert_from_user_to_utf8(const char *string)
+{
+	return FLAC_plugin__charset_convert_string(string, flac_cfg.title.user_char_set, "UTF-8");
+}
+
+GList *Charset_Create_List (void)
+{
+	GList *list = NULL;
+	guint i;
+
+	for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+		list = g_list_append(list,_(charset_trans_array[i].charset_title));
+	return list;
+}
+
+GList *Charset_Create_List_UTF8_Only (void)
+{
+	GList *list = NULL;
+
+	list = g_list_append(list,_(Charset_Get_Title_From_Name("UTF-8")));
+	return list;
+}
+
+
+/*
+ * Return charset_name from charset_title
+ */
+gchar *Charset_Get_Name_From_Title (gchar *charset_title)
+{
+	guint i;
+
+	if (charset_title)
+		for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+			if ( strcasecmp(_(charset_title),_(charset_trans_array[i].charset_title)) == 0 )
+				return charset_trans_array[i].charset_name;
+	return "";
+}
+
+
+/*
+ * Return charset_title from charset_name
+ */
+gchar *Charset_Get_Title_From_Name (gchar *charset_name)
+{
+	guint i;
+
+	if (charset_name)
+		for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+			if ( strcasecmp(charset_name,charset_trans_array[i].charset_name) == 0 )
+				return _(charset_trans_array[i].charset_title);
+	return "";
+}
diff --git a/src/plugin_xmms/charset.h b/src/plugin_xmms/charset.h
new file mode 100644
index 0000000..bb33532
--- /dev/null
+++ b/src/plugin_xmms/charset.h
@@ -0,0 +1,56 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Daisuke Shimamura
+ *
+ * Almost from charset.h - 2001/12/04
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+
+#ifndef FLAC__PLUGIN_XMMS__CHARSET_H
+#define FLAC__PLUGIN_XMMS__CHARSET_H
+
+
+/***************
+ * Declaration *
+ ***************/
+
+typedef struct {
+	gchar *charset_title;
+	gchar *charset_name;
+} CharsetInfo;
+
+/* translated charset titles */
+extern const CharsetInfo charset_trans_array[];
+
+/**************
+ * Prototypes *
+ **************/
+
+/*
+ * The returned strings are malloc()ed an must be free()d by the caller
+ */
+char *convert_from_utf8_to_user(const char *string);
+char *convert_from_user_to_utf8(const char *string);
+
+GList *Charset_Create_List (void);
+GList *Charset_Create_List_UTF8_Only (void);
+gchar *Charset_Get_Name_From_Title (gchar *charset_title);
+gchar *Charset_Get_Title_From_Name (gchar *charset_name);
+
+#endif /* __CHARSET_H__ */
+
diff --git a/src/plugin_xmms/configure.c b/src/plugin_xmms/configure.c
new file mode 100644
index 0000000..a4889c0
--- /dev/null
+++ b/src/plugin_xmms/configure.c
@@ -0,0 +1,825 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Daisuke Shimamura
+ *
+ * Based on mpg123 plugin
+ *          and prefs.c - 2000/05/06
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 2000-2002  Jerome Couderc <j.couderc@ifrance.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <pthread.h>
+#include <math.h>
+
+#include <xmms/configfile.h>
+#include <xmms/dirbrowser.h>
+#include <xmms/titlestring.h>
+#include <xmms/util.h>
+#include <xmms/plugin.h>
+
+#include "share/replaygain_synthesis.h" /* for NOISE_SHAPING_LOW */
+#include "charset.h"
+#include "configure.h"
+#include "locale_hack.h"
+
+/*
+ * Initialize Global Variable
+ */
+flac_config_t flac_cfg = {
+	/* title */
+	{
+		FALSE, /* tag_override */
+		NULL, /* tag_format */
+		FALSE, /* convert_char_set */
+		NULL /* user_char_set */
+	},
+	/* stream */
+	{
+		100 /* KB */, /* http_buffer_size */
+		50, /* http_prebuffer */
+		FALSE, /* use_proxy */
+		NULL, /* proxy_host */
+		0, /* proxy_port */
+		FALSE, /* proxy_use_auth */
+		NULL, /* proxy_user */
+		NULL, /* proxy_pass */
+		FALSE, /* save_http_stream */
+		NULL, /* save_http_path */
+		FALSE, /* cast_title_streaming */
+		FALSE /* use_udp_channel */
+	},
+	/* output */
+	{
+		/* replaygain */
+		{
+			FALSE, /* enable */
+			TRUE, /* album_mode */
+			0, /* preamp */
+			FALSE /* hard_limit */
+		},
+		/* resolution */
+		{
+			/* normal */
+			{
+				TRUE /* dither_24_to_16 */
+			},
+			/* replaygain */
+			{
+				TRUE, /* dither */
+				NOISE_SHAPING_LOW, /* noise_shaping */
+				16 /* bps_out */
+			}
+		}
+	}
+};
+
+
+static GtkWidget *flac_configurewin = NULL;
+static GtkWidget *vbox, *notebook;
+
+static GtkWidget *title_tag_override, *title_tag_box, *title_tag_entry, *title_desc;
+static GtkWidget *convert_char_set, *fileCharacterSetEntry, *userCharacterSetEntry;
+static GtkWidget *replaygain_enable, *replaygain_album_mode;
+static GtkWidget *replaygain_preamp_hscale, *replaygain_preamp_label, *replaygain_hard_limit;
+static GtkObject *replaygain_preamp;
+static GtkWidget *resolution_normal_dither_24_to_16;
+static GtkWidget *resolution_replaygain_dither;
+static GtkWidget *resolution_replaygain_noise_shaping_frame;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_none;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_low;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_medium;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_high;
+static GtkWidget *resolution_replaygain_bps_out_frame;
+static GtkWidget *resolution_replaygain_bps_out_radio_16bps;
+static GtkWidget *resolution_replaygain_bps_out_radio_24bps;
+
+static GtkObject *streaming_size_adj, *streaming_pre_adj;
+static GtkWidget *streaming_proxy_use, *streaming_proxy_host_entry;
+static GtkWidget *streaming_proxy_port_entry, *streaming_save_use, *streaming_save_entry;
+static GtkWidget *streaming_proxy_auth_use;
+static GtkWidget *streaming_proxy_auth_pass_entry, *streaming_proxy_auth_user_entry;
+static GtkWidget *streaming_proxy_auth_user_label, *streaming_proxy_auth_pass_label;
+#ifdef FLAC_ICECAST
+static GtkWidget *streaming_cast_title, *streaming_udp_title;
+#endif
+static GtkWidget *streaming_proxy_hbox, *streaming_proxy_auth_hbox, *streaming_save_dirbrowser;
+static GtkWidget *streaming_save_hbox;
+
+static gchar *gtk_entry_get_text_1 (GtkWidget *widget);
+static void flac_configurewin_ok(GtkWidget * widget, gpointer data);
+static void configure_destroy(GtkWidget * w, gpointer data);
+
+static void flac_configurewin_ok(GtkWidget * widget, gpointer data)
+{
+	ConfigFile *cfg;
+	gchar *filename;
+
+	(void)widget, (void)data; /* unused arguments */
+	g_free(flac_cfg.title.tag_format);
+	flac_cfg.title.tag_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_tag_entry)));
+	flac_cfg.title.user_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(userCharacterSetEntry));
+
+	filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL);
+	cfg = xmms_cfg_open_file(filename);
+	if (!cfg)
+		cfg = xmms_cfg_new();
+	/* title */
+	xmms_cfg_write_boolean(cfg, "flac", "title.tag_override", flac_cfg.title.tag_override);
+	xmms_cfg_write_string(cfg, "flac", "title.tag_format", flac_cfg.title.tag_format);
+	xmms_cfg_write_boolean(cfg, "flac", "title.convert_char_set", flac_cfg.title.convert_char_set);
+	xmms_cfg_write_string(cfg, "flac", "title.user_char_set", flac_cfg.title.user_char_set);
+	/* output */
+	xmms_cfg_write_boolean(cfg, "flac", "output.replaygain.enable", flac_cfg.output.replaygain.enable);
+	xmms_cfg_write_boolean(cfg, "flac", "output.replaygain.album_mode", flac_cfg.output.replaygain.album_mode);
+	xmms_cfg_write_int(cfg, "flac", "output.replaygain.preamp", flac_cfg.output.replaygain.preamp);
+	xmms_cfg_write_boolean(cfg, "flac", "output.replaygain.hard_limit", flac_cfg.output.replaygain.hard_limit);
+	xmms_cfg_write_boolean(cfg, "flac", "output.resolution.normal.dither_24_to_16", flac_cfg.output.resolution.normal.dither_24_to_16);
+	xmms_cfg_write_boolean(cfg, "flac", "output.resolution.replaygain.dither", flac_cfg.output.resolution.replaygain.dither);
+	xmms_cfg_write_int(cfg, "flac", "output.resolution.replaygain.noise_shaping", flac_cfg.output.resolution.replaygain.noise_shaping);
+	xmms_cfg_write_int(cfg, "flac", "output.resolution.replaygain.bps_out", flac_cfg.output.resolution.replaygain.bps_out);
+	/* streaming */
+	flac_cfg.stream.http_buffer_size = (gint) GTK_ADJUSTMENT(streaming_size_adj)->value;
+	flac_cfg.stream.http_prebuffer = (gint) GTK_ADJUSTMENT(streaming_pre_adj)->value;
+
+	flac_cfg.stream.use_proxy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_use));
+	if(flac_cfg.stream.proxy_host)
+		g_free(flac_cfg.stream.proxy_host);
+	flac_cfg.stream.proxy_host = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_host_entry)));
+	flac_cfg.stream.proxy_port = atoi(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_port_entry)));
+
+	flac_cfg.stream.proxy_use_auth = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_auth_use));
+
+	if(flac_cfg.stream.proxy_user)
+		g_free(flac_cfg.stream.proxy_user);
+	flac_cfg.stream.proxy_user = NULL;
+	if(strlen(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_auth_user_entry))) > 0)
+		flac_cfg.stream.proxy_user = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_auth_user_entry)));
+
+	if(flac_cfg.stream.proxy_pass)
+		g_free(flac_cfg.stream.proxy_pass);
+	flac_cfg.stream.proxy_pass = NULL;
+	if(strlen(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_auth_pass_entry))) > 0)
+		flac_cfg.stream.proxy_pass = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_auth_pass_entry)));
+
+
+	flac_cfg.stream.save_http_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use));
+	if (flac_cfg.stream.save_http_path)
+		g_free(flac_cfg.stream.save_http_path);
+	flac_cfg.stream.save_http_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_save_entry)));
+
+#ifdef FLAC_ICECAST
+	flac_cfg.stream.cast_title_streaming = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_cast_title));
+	flac_cfg.stream.use_udp_channel = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_udp_title));
+#endif
+
+	xmms_cfg_write_int(cfg, "flac", "stream.http_buffer_size", flac_cfg.stream.http_buffer_size);
+	xmms_cfg_write_int(cfg, "flac", "stream.http_prebuffer", flac_cfg.stream.http_prebuffer);
+	xmms_cfg_write_boolean(cfg, "flac", "stream.use_proxy", flac_cfg.stream.use_proxy);
+	xmms_cfg_write_string(cfg, "flac", "stream.proxy_host", flac_cfg.stream.proxy_host);
+	xmms_cfg_write_int(cfg, "flac", "stream.proxy_port", flac_cfg.stream.proxy_port);
+	xmms_cfg_write_boolean(cfg, "flac", "stream.proxy_use_auth", flac_cfg.stream.proxy_use_auth);
+	if(flac_cfg.stream.proxy_user)
+		xmms_cfg_write_string(cfg, "flac", "stream.proxy_user", flac_cfg.stream.proxy_user);
+	else
+		xmms_cfg_remove_key(cfg, "flac", "stream.proxy_user");
+	if(flac_cfg.stream.proxy_pass)
+		xmms_cfg_write_string(cfg, "flac", "stream.proxy_pass", flac_cfg.stream.proxy_pass);
+	else
+		xmms_cfg_remove_key(cfg, "flac", "stream.proxy_pass");
+	xmms_cfg_write_boolean(cfg, "flac", "stream.save_http_stream", flac_cfg.stream.save_http_stream);
+	xmms_cfg_write_string(cfg, "flac", "stream.save_http_path", flac_cfg.stream.save_http_path);
+#ifdef FLAC_ICECAST
+	xmms_cfg_write_boolean(cfg, "flac", "stream.cast_title_streaming", flac_cfg.stream.cast_title_streaming);
+	xmms_cfg_write_boolean(cfg, "flac", "stream.use_udp_channel", flac_cfg.stream.use_udp_channel);
+#endif
+
+	xmms_cfg_write_file(cfg, filename);
+	xmms_cfg_free(cfg);
+	g_free(filename);
+	gtk_widget_destroy(flac_configurewin);
+}
+
+static void configure_destroy(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+}
+
+static void title_tag_override_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.title.tag_override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_tag_override));
+
+	gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override);
+	gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override);
+
+}
+
+static void convert_char_set_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.title.convert_char_set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(convert_char_set));
+
+	gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE);
+	gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
+}
+
+static void replaygain_enable_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.replaygain.enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_enable));
+
+	gtk_widget_set_sensitive(replaygain_album_mode, flac_cfg.output.replaygain.enable);
+	gtk_widget_set_sensitive(replaygain_preamp_hscale, flac_cfg.output.replaygain.enable);
+	gtk_widget_set_sensitive(replaygain_hard_limit, flac_cfg.output.replaygain.enable);
+}
+
+static void replaygain_album_mode_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.replaygain.album_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_album_mode));
+}
+
+static void replaygain_hard_limit_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.replaygain.hard_limit = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit));
+}
+
+static void replaygain_preamp_cb(GtkWidget *widget, gpointer data)
+{
+	GString *gstring = g_string_new("");
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.replaygain.preamp = (int) floor(GTK_ADJUSTMENT(replaygain_preamp)->value + 0.5);
+
+	g_string_sprintf(gstring, "%i dB", flac_cfg.output.replaygain.preamp);
+	gtk_label_set_text(GTK_LABEL(replaygain_preamp_label), _(gstring->str));
+}
+
+static void resolution_normal_dither_24_to_16_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.resolution.normal.dither_24_to_16 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16));
+}
+
+static void resolution_replaygain_dither_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.resolution.replaygain.dither = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither));
+
+	gtk_widget_set_sensitive(resolution_replaygain_noise_shaping_frame, flac_cfg.output.resolution.replaygain.dither);
+}
+
+static void resolution_replaygain_noise_shaping_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.resolution.replaygain.noise_shaping =
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none))? 0 :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low))? 1 :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium))? 2 :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high))? 3 :
+		0
+	;
+}
+
+static void resolution_replaygain_bps_out_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.resolution.replaygain.bps_out =
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps))? 16 :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps))? 24 :
+		16
+	;
+}
+
+static void proxy_use_cb(GtkWidget * w, gpointer data)
+{
+	gboolean use_proxy, use_proxy_auth;
+	(void) w;
+	(void) data;
+
+	use_proxy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_use));
+	use_proxy_auth = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_auth_use));
+
+	gtk_widget_set_sensitive(streaming_proxy_hbox, use_proxy);
+	gtk_widget_set_sensitive(streaming_proxy_auth_use, use_proxy);
+	gtk_widget_set_sensitive(streaming_proxy_auth_hbox, use_proxy && use_proxy_auth);
+}
+
+static void proxy_auth_use_cb(GtkWidget *w, gpointer data)
+{
+	gboolean use_proxy, use_proxy_auth;
+	(void) w;
+	(void) data;
+
+	use_proxy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_use));
+	use_proxy_auth = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_auth_use));
+
+	gtk_widget_set_sensitive(streaming_proxy_auth_hbox, use_proxy && use_proxy_auth);
+}
+
+static void streaming_save_dirbrowser_cb(gchar * dir)
+{
+	gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), dir);
+}
+
+static void streaming_save_browse_cb(GtkWidget * w, gpointer data)
+{
+	(void) w;
+	(void) data;
+	if (!streaming_save_dirbrowser)
+	{
+		streaming_save_dirbrowser = xmms_create_dir_browser(_("Select the directory where you want to store the MPEG streams:"),
+								    flac_cfg.stream.save_http_path, GTK_SELECTION_SINGLE, streaming_save_dirbrowser_cb);
+		gtk_signal_connect(GTK_OBJECT(streaming_save_dirbrowser), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &streaming_save_dirbrowser);
+		gtk_window_set_transient_for(GTK_WINDOW(streaming_save_dirbrowser), GTK_WINDOW(flac_configurewin));
+		gtk_widget_show(streaming_save_dirbrowser);
+	}
+}
+
+static void streaming_save_use_cb(GtkWidget * w, gpointer data)
+{
+	gboolean save_stream;
+	(void) w;
+	(void) data;
+
+	save_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use));
+
+	gtk_widget_set_sensitive(streaming_save_hbox, save_stream);
+}
+
+
+void FLAC_XMMS__configure(void)
+{
+	GtkWidget *title_frame, *title_tag_vbox, *title_tag_label;
+	GtkWidget *replaygain_frame, *resolution_frame, *output_vbox, *resolution_normal_frame, *resolution_replaygain_frame;
+	GtkWidget *replaygain_vbox, *resolution_hbox, *resolution_normal_vbox, *resolution_replaygain_vbox;
+	GtkWidget *resolution_replaygain_noise_shaping_vbox;
+	GtkWidget *resolution_replaygain_bps_out_vbox;
+	GtkWidget *label, *hbox;
+	GtkWidget *bbox, *ok, *cancel;
+	GList *list;
+
+	GtkWidget *streaming_vbox;
+	GtkWidget *streaming_buf_frame, *streaming_buf_hbox;
+	GtkWidget *streaming_size_box, *streaming_size_label, *streaming_size_spin;
+	GtkWidget *streaming_pre_box, *streaming_pre_label, *streaming_pre_spin;
+	GtkWidget *streaming_proxy_frame, *streaming_proxy_vbox;
+	GtkWidget *streaming_proxy_port_label, *streaming_proxy_host_label;
+	GtkWidget *streaming_save_frame, *streaming_save_vbox;
+	GtkWidget *streaming_save_label, *streaming_save_browse;
+#ifdef FLAC_ICECAST
+	GtkWidget *streaming_cast_frame, *streaming_cast_vbox;
+#endif
+	char *temp;
+
+	if (flac_configurewin != NULL) {
+		gdk_window_raise(flac_configurewin->window);
+		return;
+	}
+	flac_configurewin = gtk_window_new(GTK_WINDOW_DIALOG);
+	gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &flac_configurewin);
+	gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(configure_destroy), &flac_configurewin);
+	gtk_window_set_title(GTK_WINDOW(flac_configurewin), _("Flac Configuration"));
+	gtk_window_set_policy(GTK_WINDOW(flac_configurewin), FALSE, FALSE, FALSE);
+	gtk_container_border_width(GTK_CONTAINER(flac_configurewin), 10);
+
+	vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_add(GTK_CONTAINER(flac_configurewin), vbox);
+
+	notebook = gtk_notebook_new();
+	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+	/* Title config.. */
+
+	title_frame = gtk_frame_new(_("Tag Handling"));
+	gtk_container_border_width(GTK_CONTAINER(title_frame), 5);
+
+	title_tag_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(title_tag_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(title_frame), title_tag_vbox);
+
+	/* Convert Char Set */
+
+	convert_char_set = gtk_check_button_new_with_label(_("Convert Character Set"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(convert_char_set), flac_cfg.title.convert_char_set);
+	gtk_signal_connect(GTK_OBJECT(convert_char_set), "clicked", convert_char_set_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(title_tag_vbox), convert_char_set, FALSE, FALSE, 0);
+	/*  Combo boxes... */
+	hbox = gtk_hbox_new(FALSE,4);
+	gtk_container_add(GTK_CONTAINER(title_tag_vbox),hbox);
+	label = gtk_label_new(_("Convert character set from :"));
+	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+	fileCharacterSetEntry = gtk_combo_new();
+	gtk_box_pack_start(GTK_BOX(hbox),fileCharacterSetEntry,TRUE,TRUE,0);
+
+	label = gtk_label_new (_("to :"));
+	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+	userCharacterSetEntry = gtk_combo_new();
+	gtk_box_pack_start(GTK_BOX(hbox),userCharacterSetEntry,TRUE,TRUE,0);
+
+	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),FALSE);
+	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),FALSE);
+	gtk_combo_set_value_in_list(GTK_COMBO(fileCharacterSetEntry),TRUE,FALSE);
+	gtk_combo_set_value_in_list(GTK_COMBO(userCharacterSetEntry),TRUE,FALSE);
+
+	list = Charset_Create_List();
+	gtk_combo_set_popdown_strings(GTK_COMBO(fileCharacterSetEntry),Charset_Create_List_UTF8_Only());
+	gtk_combo_set_popdown_strings(GTK_COMBO(userCharacterSetEntry),list);
+	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.title.user_char_set));
+	gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE);
+	gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
+
+	/* Override Tagging Format */
+
+	title_tag_override = gtk_check_button_new_with_label(_("Override generic titles"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_tag_override), flac_cfg.title.tag_override);
+	gtk_signal_connect(GTK_OBJECT(title_tag_override), "clicked", title_tag_override_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_override, FALSE, FALSE, 0);
+
+	title_tag_box = gtk_hbox_new(FALSE, 5);
+	gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override);
+	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_box, FALSE, FALSE, 0);
+
+	title_tag_label = gtk_label_new(_("Title format:"));
+	gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_label, FALSE, FALSE, 0);
+
+	title_tag_entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(title_tag_entry), flac_cfg.title.tag_format);
+	gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_entry, TRUE, TRUE, 0);
+
+	title_desc = xmms_titlestring_descriptions("pafFetnygc", 2);
+	gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override);
+	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_desc, FALSE, FALSE, 0);
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), title_frame, gtk_label_new(_("Title")));
+
+	/* Output config.. */
+
+	output_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(output_vbox), 5);
+
+	/* replaygain */
+
+	replaygain_frame = gtk_frame_new(_("ReplayGain"));
+	gtk_container_border_width(GTK_CONTAINER(replaygain_frame), 5);
+	gtk_box_pack_start(GTK_BOX(output_vbox), replaygain_frame, TRUE, TRUE, 0);
+
+	replaygain_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(replaygain_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(replaygain_frame), replaygain_vbox);
+
+	replaygain_enable = gtk_check_button_new_with_label(_("Enable ReplayGain processing"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_enable), flac_cfg.output.replaygain.enable);
+	gtk_signal_connect(GTK_OBJECT(replaygain_enable), "clicked", replaygain_enable_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_enable, FALSE, FALSE, 0);
+
+	replaygain_album_mode = gtk_check_button_new_with_label(_("Album mode"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_album_mode), flac_cfg.output.replaygain.album_mode);
+	gtk_signal_connect(GTK_OBJECT(replaygain_album_mode), "clicked", replaygain_album_mode_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_album_mode, FALSE, FALSE, 0);
+
+	hbox = gtk_hbox_new(FALSE,3);
+	gtk_container_add(GTK_CONTAINER(replaygain_vbox),hbox);
+	label = gtk_label_new(_("Preamp:"));
+	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+	replaygain_preamp = gtk_adjustment_new(flac_cfg.output.replaygain.preamp, -24.0, +24.0, 1.0, 6.0, 0.0);
+	gtk_signal_connect(GTK_OBJECT(replaygain_preamp), "value-changed", replaygain_preamp_cb, NULL);
+	replaygain_preamp_hscale = gtk_hscale_new(GTK_ADJUSTMENT(replaygain_preamp));
+	gtk_scale_set_draw_value(GTK_SCALE(replaygain_preamp_hscale), FALSE);
+	gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_hscale,TRUE,TRUE,0);
+	replaygain_preamp_label = gtk_label_new(_("0 dB"));
+	gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_label,FALSE,FALSE,0);
+	gtk_adjustment_value_changed(GTK_ADJUSTMENT(replaygain_preamp));
+
+	replaygain_hard_limit = gtk_check_button_new_with_label(_("6dB hard limiting"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit), flac_cfg.output.replaygain.hard_limit);
+	gtk_signal_connect(GTK_OBJECT(replaygain_hard_limit), "clicked", replaygain_hard_limit_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_hard_limit, FALSE, FALSE, 0);
+
+	replaygain_enable_cb(replaygain_enable, NULL);
+
+	/* resolution */
+
+	resolution_frame = gtk_frame_new(_("Resolution"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_frame), 5);
+	gtk_box_pack_start(GTK_BOX(output_vbox), resolution_frame, TRUE, TRUE, 0);
+
+	resolution_hbox = gtk_hbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(resolution_hbox), 5);
+	gtk_container_add(GTK_CONTAINER(resolution_frame), resolution_hbox);
+
+	resolution_normal_frame = gtk_frame_new(_("Without ReplayGain"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_normal_frame), 5);
+	gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_normal_frame, TRUE, TRUE, 0);
+
+	resolution_normal_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(resolution_normal_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(resolution_normal_frame), resolution_normal_vbox);
+
+	resolution_normal_dither_24_to_16 = gtk_check_button_new_with_label(_("Dither 24bps to 16bps"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16), flac_cfg.output.resolution.normal.dither_24_to_16);
+	gtk_signal_connect(GTK_OBJECT(resolution_normal_dither_24_to_16), "clicked", resolution_normal_dither_24_to_16_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(resolution_normal_vbox), resolution_normal_dither_24_to_16, FALSE, FALSE, 0);
+
+	resolution_replaygain_frame = gtk_frame_new(_("With ReplayGain"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_frame), 5);
+	gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_replaygain_frame, TRUE, TRUE, 0);
+
+	resolution_replaygain_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_frame), resolution_replaygain_vbox);
+
+	resolution_replaygain_dither = gtk_check_button_new_with_label(_("Enable dithering"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither), flac_cfg.output.resolution.replaygain.dither);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_dither), "clicked", resolution_replaygain_dither_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), resolution_replaygain_dither, FALSE, FALSE, 0);
+
+	hbox = gtk_hbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(hbox), 5);
+	gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), hbox, TRUE, TRUE, 0);
+
+	resolution_replaygain_noise_shaping_frame = gtk_frame_new(_("Noise shaping"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), 5);
+	gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_noise_shaping_frame, TRUE, TRUE, 0);
+
+	resolution_replaygain_noise_shaping_vbox = gtk_vbutton_box_new();
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), resolution_replaygain_noise_shaping_vbox);
+
+	resolution_replaygain_noise_shaping_radio_none = gtk_radio_button_new_with_label(NULL, _("none"));
+	if(flac_cfg.output.resolution.replaygain.noise_shaping == 0)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_none), "clicked", resolution_replaygain_noise_shaping_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_none);
+
+	resolution_replaygain_noise_shaping_radio_low = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("low"));
+	if(flac_cfg.output.resolution.replaygain.noise_shaping == 1)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_low), "clicked", resolution_replaygain_noise_shaping_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_low);
+
+	resolution_replaygain_noise_shaping_radio_medium = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("medium"));
+	if(flac_cfg.output.resolution.replaygain.noise_shaping == 2)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_medium), "clicked", resolution_replaygain_noise_shaping_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_medium);
+
+	resolution_replaygain_noise_shaping_radio_high = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("high"));
+	if(flac_cfg.output.resolution.replaygain.noise_shaping == 3)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_high), "clicked", resolution_replaygain_noise_shaping_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_high);
+
+	resolution_replaygain_bps_out_frame = gtk_frame_new(_("Dither to"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_frame), 5);
+	gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_bps_out_frame, FALSE, FALSE, 0);
+
+	resolution_replaygain_bps_out_vbox = gtk_vbutton_box_new();
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), 0);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_frame), resolution_replaygain_bps_out_vbox);
+
+	resolution_replaygain_bps_out_radio_16bps = gtk_radio_button_new_with_label(NULL, _("16 bps"));
+	if(flac_cfg.output.resolution.replaygain.bps_out == 16)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_16bps), "clicked", resolution_replaygain_bps_out_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_16bps);
+
+	resolution_replaygain_bps_out_radio_24bps = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_bps_out_radio_16bps), _("24 bps"));
+	if(flac_cfg.output.resolution.replaygain.bps_out == 24)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_24bps), "clicked", resolution_replaygain_bps_out_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_24bps);
+
+	resolution_replaygain_dither_cb(resolution_replaygain_dither, NULL);
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), output_vbox, gtk_label_new(_("Output")));
+
+	/* Streaming */
+
+	streaming_vbox = gtk_vbox_new(FALSE, 0);
+
+	streaming_buf_frame = gtk_frame_new(_("Buffering:"));
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_frame), 5);
+	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_buf_frame, FALSE, FALSE, 0);
+
+	streaming_buf_hbox = gtk_hbox_new(TRUE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_hbox), 5);
+	gtk_container_add(GTK_CONTAINER(streaming_buf_frame), streaming_buf_hbox);
+
+	streaming_size_box = gtk_hbox_new(FALSE, 5);
+	/*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_size_box,0,1,0,1); */
+	gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_size_box, TRUE, TRUE, 0);
+	streaming_size_label = gtk_label_new(_("Buffer size (kb):"));
+	gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_label, FALSE, FALSE, 0);
+	streaming_size_adj = gtk_adjustment_new(flac_cfg.stream.http_buffer_size, 4, 4096, 4, 4, 4);
+	streaming_size_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_size_adj), 8, 0);
+	gtk_widget_set_usize(streaming_size_spin, 60, -1);
+	gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_spin, FALSE, FALSE, 0);
+
+	streaming_pre_box = gtk_hbox_new(FALSE, 5);
+	/*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_pre_box,1,2,0,1); */
+	gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_pre_box, TRUE, TRUE, 0);
+	streaming_pre_label = gtk_label_new(_("Pre-buffer (percent):"));
+	gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_label, FALSE, FALSE, 0);
+	streaming_pre_adj = gtk_adjustment_new(flac_cfg.stream.http_prebuffer, 0, 90, 1, 1, 1);
+	streaming_pre_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_pre_adj), 1, 0);
+	gtk_widget_set_usize(streaming_pre_spin, 60, -1);
+	gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_spin, FALSE, FALSE, 0);
+
+ 	/*
+ 	 * Proxy config.
+ 	 */
+	streaming_proxy_frame = gtk_frame_new(_("Proxy:"));
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_proxy_frame), 5);
+	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_proxy_frame, FALSE, FALSE, 0);
+
+	streaming_proxy_vbox = gtk_vbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_proxy_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(streaming_proxy_frame), streaming_proxy_vbox);
+
+	streaming_proxy_use = gtk_check_button_new_with_label(_("Use proxy"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_proxy_use), flac_cfg.stream.use_proxy);
+	gtk_signal_connect(GTK_OBJECT(streaming_proxy_use), "clicked", GTK_SIGNAL_FUNC(proxy_use_cb), NULL);
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_vbox), streaming_proxy_use, FALSE, FALSE, 0);
+
+	streaming_proxy_hbox = gtk_hbox_new(FALSE, 5);
+	gtk_widget_set_sensitive(streaming_proxy_hbox, flac_cfg.stream.use_proxy);
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_vbox), streaming_proxy_hbox, FALSE, FALSE, 0);
+
+	streaming_proxy_host_label = gtk_label_new(_("Host:"));
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_hbox), streaming_proxy_host_label, FALSE, FALSE, 0);
+
+	streaming_proxy_host_entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(streaming_proxy_host_entry), flac_cfg.stream.proxy_host? flac_cfg.stream.proxy_host : "");
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_hbox), streaming_proxy_host_entry, TRUE, TRUE, 0);
+
+	streaming_proxy_port_label = gtk_label_new(_("Port:"));
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_hbox), streaming_proxy_port_label, FALSE, FALSE, 0);
+
+	streaming_proxy_port_entry = gtk_entry_new();
+	gtk_widget_set_usize(streaming_proxy_port_entry, 50, -1);
+	temp = g_strdup_printf("%d", flac_cfg.stream.proxy_port);
+	gtk_entry_set_text(GTK_ENTRY(streaming_proxy_port_entry), temp);
+	g_free(temp);
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_hbox), streaming_proxy_port_entry, FALSE, FALSE, 0);
+
+	streaming_proxy_auth_use = gtk_check_button_new_with_label(_("Use authentication"));
+	gtk_widget_set_sensitive(streaming_proxy_auth_use, flac_cfg.stream.use_proxy);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_proxy_auth_use), flac_cfg.stream.proxy_use_auth);
+	gtk_signal_connect(GTK_OBJECT(streaming_proxy_auth_use), "clicked", GTK_SIGNAL_FUNC(proxy_auth_use_cb), NULL);
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_vbox), streaming_proxy_auth_use, FALSE, FALSE, 0);
+
+	streaming_proxy_auth_hbox = gtk_hbox_new(FALSE, 5);
+	gtk_widget_set_sensitive(streaming_proxy_auth_hbox, flac_cfg.stream.use_proxy && flac_cfg.stream.proxy_use_auth);
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_vbox), streaming_proxy_auth_hbox, FALSE, FALSE, 0);
+
+	streaming_proxy_auth_user_label = gtk_label_new(_("Username:"));
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_auth_hbox), streaming_proxy_auth_user_label, FALSE, FALSE, 0);
+
+	streaming_proxy_auth_user_entry = gtk_entry_new();
+	if(flac_cfg.stream.proxy_user)
+		gtk_entry_set_text(GTK_ENTRY(streaming_proxy_auth_user_entry), flac_cfg.stream.proxy_user);
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_auth_hbox), streaming_proxy_auth_user_entry, TRUE, TRUE, 0);
+
+	streaming_proxy_auth_pass_label = gtk_label_new(_("Password:"));
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_auth_hbox), streaming_proxy_auth_pass_label, FALSE, FALSE, 0);
+
+	streaming_proxy_auth_pass_entry = gtk_entry_new();
+	if(flac_cfg.stream.proxy_pass)
+		gtk_entry_set_text(GTK_ENTRY(streaming_proxy_auth_pass_entry), flac_cfg.stream.proxy_pass);
+	gtk_entry_set_visibility(GTK_ENTRY(streaming_proxy_auth_pass_entry), FALSE);
+	gtk_box_pack_start(GTK_BOX(streaming_proxy_auth_hbox), streaming_proxy_auth_pass_entry, TRUE, TRUE, 0);
+
+
+	/*
+	 * Save to disk config.
+	 */
+	streaming_save_frame = gtk_frame_new(_("Save stream to disk:"));
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_save_frame), 5);
+	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_save_frame, FALSE, FALSE, 0);
+
+	streaming_save_vbox = gtk_vbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_save_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(streaming_save_frame), streaming_save_vbox);
+
+	streaming_save_use = gtk_check_button_new_with_label(_("Save stream to disk"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_save_use), flac_cfg.stream.save_http_stream);
+	gtk_signal_connect(GTK_OBJECT(streaming_save_use), "clicked", GTK_SIGNAL_FUNC(streaming_save_use_cb), NULL);
+	gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_use, FALSE, FALSE, 0);
+
+	streaming_save_hbox = gtk_hbox_new(FALSE, 5);
+	gtk_widget_set_sensitive(streaming_save_hbox, flac_cfg.stream.save_http_stream);
+	gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_hbox, FALSE, FALSE, 0);
+
+	streaming_save_label = gtk_label_new(_("Path:"));
+	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_label, FALSE, FALSE, 0);
+
+	streaming_save_entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), flac_cfg.stream.save_http_path? flac_cfg.stream.save_http_path : "");
+	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_entry, TRUE, TRUE, 0);
+
+	streaming_save_browse = gtk_button_new_with_label(_("Browse"));
+	gtk_signal_connect(GTK_OBJECT(streaming_save_browse), "clicked", GTK_SIGNAL_FUNC(streaming_save_browse_cb), NULL);
+	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_browse, FALSE, FALSE, 0);
+
+#ifdef FLAC_ICECAST
+	streaming_cast_frame = gtk_frame_new(_("SHOUT/Icecast:"));
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_cast_frame), 5);
+	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_cast_frame, FALSE, FALSE, 0);
+
+	streaming_cast_vbox = gtk_vbox_new(5, FALSE);
+	gtk_container_add(GTK_CONTAINER(streaming_cast_frame), streaming_cast_vbox);
+
+	streaming_cast_title = gtk_check_button_new_with_label(_("Enable SHOUT/Icecast title streaming"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_cast_title), flac_cfg.stream.cast_title_streaming);
+	gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_cast_title, FALSE, FALSE, 0);
+
+	streaming_udp_title = gtk_check_button_new_with_label(_("Enable Icecast Metadata UDP Channel"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_udp_title), flac_cfg.stream.use_udp_channel);
+	gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_udp_title, FALSE, FALSE, 0);
+#endif
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), streaming_vbox, gtk_label_new(_("Streaming")));
+
+	/* Buttons */
+
+	bbox = gtk_hbutton_box_new();
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+	gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+
+	ok = gtk_button_new_with_label(_("Ok"));
+	gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(flac_configurewin_ok), NULL);
+	GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
+	gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
+	gtk_widget_grab_default(ok);
+
+	cancel = gtk_button_new_with_label(_("Cancel"));
+	gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(flac_configurewin));
+	GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+	gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+	gtk_widget_show_all(flac_configurewin);
+}
+
+void FLAC_XMMS__aboutbox(void)
+{
+	static GtkWidget *about_window;
+
+	if (about_window)
+		gdk_window_raise(about_window->window);
+
+	about_window = xmms_show_message(
+		_("About Flac Plugin"),
+		_("Flac Plugin by Josh Coalson\n"
+		  "contributions by\n"
+		  "......\n"
+		  "......\n"
+		  "and\n"
+		  "Daisuke Shimamura\n"
+		  "Visit http://xiph.org/flac/"),
+		_("Ok"), FALSE, NULL, NULL);
+	gtk_signal_connect(GTK_OBJECT(about_window), "destroy",
+			   GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+			   &about_window);
+}
+
+/*
+ * Get text of an Entry or a ComboBox
+ */
+static gchar *gtk_entry_get_text_1 (GtkWidget *widget)
+{
+	if (GTK_IS_COMBO(widget))
+	{
+		return gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(widget)->entry));
+	}else if (GTK_IS_ENTRY(widget))
+	{
+		return gtk_entry_get_text(GTK_ENTRY(widget));
+	}else
+	{
+		return NULL;
+	}
+}
diff --git a/src/plugin_xmms/configure.h b/src/plugin_xmms/configure.h
new file mode 100644
index 0000000..6cde139
--- /dev/null
+++ b/src/plugin_xmms/configure.h
@@ -0,0 +1,77 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Daisuke Shimamura
+ *
+ * Based on mpg123 plugin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__PLUGIN_XMMS__CONFIGURE_H
+#define FLAC__PLUGIN_XMMS__CONFIGURE_H
+
+#include <glib.h>
+
+typedef struct {
+	struct {
+		gboolean tag_override;
+		gchar *tag_format;
+		gboolean convert_char_set;
+		gchar *user_char_set;
+	} title;
+
+	struct {
+		gint http_buffer_size;
+		gint http_prebuffer;
+		gboolean use_proxy;
+		gchar *proxy_host;
+		gint proxy_port;
+		gboolean proxy_use_auth;
+		gchar *proxy_user;
+		gchar *proxy_pass;
+		gboolean save_http_stream;
+		gchar *save_http_path;
+		gboolean cast_title_streaming;
+		gboolean use_udp_channel;
+	} stream;
+
+	struct {
+		struct {
+			gboolean enable;
+			gboolean album_mode;
+			gint preamp;
+			gboolean hard_limit;
+		} replaygain;
+		struct {
+			struct {
+				gboolean dither_24_to_16;
+			} normal;
+			struct {
+				gboolean dither;
+				gint noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */
+				gint bps_out;
+			} replaygain;
+		} resolution;
+	} output;
+} flac_config_t;
+
+extern flac_config_t flac_cfg;
+
+extern void FLAC_XMMS__configure(void);
+extern void FLAC_XMMS__aboutbox(void);
+
+#endif
+
+
+
diff --git a/src/plugin_xmms/fileinfo.c b/src/plugin_xmms/fileinfo.c
new file mode 100644
index 0000000..8eb1e11
--- /dev/null
+++ b/src/plugin_xmms/fileinfo.c
@@ -0,0 +1,495 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *  Copyright (C) 1999,2000  Håvard Kvålen
+ *  Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Daisuke Shimamura
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h> /* for strlen() */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <gtk/gtk.h>
+
+#include "FLAC/metadata.h"
+#include "charset.h"
+#include "configure.h"
+#include "plugin_common/replaygain.h"
+#include "plugin_common/tags.h"
+#include "locale_hack.h"
+
+static GtkWidget *window = NULL;
+static GList *genre_list = NULL;
+static GtkWidget *filename_entry, *tag_frame;
+static GtkWidget *title_entry, *artist_entry, *album_entry, *date_entry, *tracknum_entry, *comment_entry;
+static GtkWidget *replaygain_reference, *replaygain_track_gain, *replaygain_album_gain, *replaygain_track_peak, *replaygain_album_peak;
+static GtkWidget *genre_combo;
+static GtkWidget *flac_samplerate, *flac_channels, *flac_bits_per_sample, *flac_blocksize, *flac_filesize, *flac_samples, *flac_bitrate;
+
+static gchar *current_filename = NULL;
+static FLAC__StreamMetadata *tags_ = NULL;
+
+static const gchar *vorbis_genres[] =
+{
+	N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"),
+	N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"),
+	N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"),
+	N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"),
+	N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"),
+	N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"),
+	N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"),
+	N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"),
+	N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"),
+	N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("Alt"),
+	N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"),
+	N_("Meditative"), N_("Instrumental Pop"),
+	N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"),
+	N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"),
+	N_("Pop-Folk"), N_("Eurodance"), N_("Dream"),
+	N_("Southern Rock"), N_("Comedy"), N_("Cult"),
+	N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"),
+	N_("Pop/Funk"), N_("Jungle"), N_("Native American"),
+	N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"),
+	N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"),
+	N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"),
+	N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"),
+	N_("Folk/Rock"), N_("National Folk"), N_("Swing"),
+	N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"),
+	N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"),
+	N_("Gothic Rock"), N_("Progressive Rock"),
+	N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"),
+	N_("Big Band"), N_("Chorus"), N_("Easy Listening"),
+	N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"),
+	N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"),
+	N_("Booty Bass"), N_("Primus"), N_("Porn Groove"),
+	N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"),
+	N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"),
+	N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"),
+	N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"),
+	N_("Euro-House"), N_("Dance Hall"), N_("Goa"),
+	N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"),
+	N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"),
+	N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"),
+	N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"),
+	N_("Contemporary Christian"), N_("Christian Rock"),
+	N_("Merengue"), N_("Salsa"), N_("Thrash Metal"),
+	N_("Anime"), N_("JPop"), N_("Synthpop")
+};
+
+static void label_set_text(GtkWidget * label, char *str, ...)
+{
+	va_list args;
+	gchar *tempstr;
+
+	va_start(args, str);
+	tempstr = g_strdup_vprintf(str, args);
+	va_end(args);
+
+	gtk_label_set_text(GTK_LABEL(label), tempstr);
+	g_free(tempstr);
+}
+
+static void set_entry_tag(GtkEntry * entry, const char * utf8)
+{
+	if(utf8) {
+		if(flac_cfg.title.convert_char_set) {
+			char *text = convert_from_utf8_to_user(utf8);
+			gtk_entry_set_text(entry, text);
+			free(text);
+		}
+		else
+			gtk_entry_set_text(entry, utf8);
+	}
+	else
+		gtk_entry_set_text(entry, "");
+}
+
+static void get_entry_tag(GtkEntry * entry, const char *name)
+{
+	gchar *text;
+	char *utf8;
+
+	text = gtk_entry_get_text(entry);
+	if (!text || strlen(text) == 0)
+		return;
+	if(flac_cfg.title.convert_char_set)
+		utf8 = convert_from_user_to_utf8(text);
+	else
+		utf8 = text;
+
+	FLAC_plugin__tags_add_tag_utf8(tags_, name, utf8, /*separator=*/0);
+
+	if(flac_cfg.title.convert_char_set)
+		free(utf8);
+}
+
+static void show_tag(void)
+{
+	set_entry_tag(GTK_ENTRY(title_entry)                  , FLAC_plugin__tags_get_tag_utf8(tags_, "TITLE"));
+	set_entry_tag(GTK_ENTRY(artist_entry)                 , FLAC_plugin__tags_get_tag_utf8(tags_, "ARTIST"));
+	set_entry_tag(GTK_ENTRY(album_entry)                  , FLAC_plugin__tags_get_tag_utf8(tags_, "ALBUM"));
+	set_entry_tag(GTK_ENTRY(date_entry)                   , FLAC_plugin__tags_get_tag_utf8(tags_, "DATE"));
+	set_entry_tag(GTK_ENTRY(tracknum_entry)               , FLAC_plugin__tags_get_tag_utf8(tags_, "TRACKNUMBER"));
+	set_entry_tag(GTK_ENTRY(comment_entry)                , FLAC_plugin__tags_get_tag_utf8(tags_, "DESCRIPTION"));
+	set_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), FLAC_plugin__tags_get_tag_utf8(tags_, "GENRE"));
+}
+
+static void save_tag(GtkWidget * w, gpointer data)
+{
+	(void)w;
+	(void)data;
+
+	FLAC_plugin__tags_delete_tag(tags_, "TITLE");
+	FLAC_plugin__tags_delete_tag(tags_, "ARTIST");
+	FLAC_plugin__tags_delete_tag(tags_, "ALBUM");
+	FLAC_plugin__tags_delete_tag(tags_, "DATE");
+	FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER");
+	FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION");
+	FLAC_plugin__tags_delete_tag(tags_, "GENRE");
+
+	get_entry_tag(GTK_ENTRY(title_entry)                  , "TITLE");
+	get_entry_tag(GTK_ENTRY(artist_entry)                 , "ARTIST");
+	get_entry_tag(GTK_ENTRY(album_entry)                  , "ALBUM");
+	get_entry_tag(GTK_ENTRY(date_entry)                   , "DATE");
+	get_entry_tag(GTK_ENTRY(tracknum_entry)               , "TRACKNUMBER");
+	get_entry_tag(GTK_ENTRY(comment_entry)                , "DESCRIPTION");
+	get_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), "GENRE");
+
+	FLAC_plugin__tags_set(current_filename, tags_);
+	gtk_widget_destroy(window);
+}
+
+static void remove_tag(GtkWidget * w, gpointer data)
+{
+	(void)w;
+	(void)data;
+
+	FLAC_plugin__tags_delete_tag(tags_, "TITLE");
+	FLAC_plugin__tags_delete_tag(tags_, "ARTIST");
+	FLAC_plugin__tags_delete_tag(tags_, "ALBUM");
+	FLAC_plugin__tags_delete_tag(tags_, "DATE");
+	FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER");
+	FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION");
+	FLAC_plugin__tags_delete_tag(tags_, "GENRE");
+
+	FLAC_plugin__tags_set(current_filename, tags_);
+	gtk_widget_destroy(window);
+}
+
+static void show_file_info(void)
+{
+	FLAC__StreamMetadata streaminfo;
+	struct stat _stat;
+
+	gtk_label_set_text(GTK_LABEL(flac_samplerate), "");
+	gtk_label_set_text(GTK_LABEL(flac_channels), "");
+	gtk_label_set_text(GTK_LABEL(flac_bits_per_sample), "");
+	gtk_label_set_text(GTK_LABEL(flac_blocksize), "");
+	gtk_label_set_text(GTK_LABEL(flac_filesize), "");
+	gtk_label_set_text(GTK_LABEL(flac_samples), "");
+	gtk_label_set_text(GTK_LABEL(flac_bitrate), "");
+
+	if(!FLAC__metadata_get_streaminfo(current_filename, &streaminfo)) {
+		return;
+	}
+
+	label_set_text(flac_samplerate, _("Samplerate: %d Hz"), streaminfo.data.stream_info.sample_rate);
+	label_set_text(flac_channels, _("Channels: %d"), streaminfo.data.stream_info.channels);
+	label_set_text(flac_bits_per_sample, _("Bits/Sample: %d"), streaminfo.data.stream_info.bits_per_sample);
+	if(streaminfo.data.stream_info.min_blocksize == streaminfo.data.stream_info.max_blocksize)
+		label_set_text(flac_blocksize, _("Blocksize: %d"), streaminfo.data.stream_info.min_blocksize);
+	else
+		label_set_text(flac_blocksize, _("Blocksize: variable\n  min/max: %d/%d"), streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize);
+
+	if (streaminfo.data.stream_info.total_samples)
+		label_set_text(flac_samples, _("Samples: %" PRIu64 "\nLength: %d:%.2d"),
+				streaminfo.data.stream_info.total_samples,
+				(int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate / 60),
+				(int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate % 60));
+
+	if(!stat(current_filename, &_stat) && S_ISREG(_stat.st_mode)) {
+		label_set_text(flac_filesize, _("Filesize: %zd B"), _stat.st_size);
+		if (streaminfo.data.stream_info.total_samples)
+			label_set_text(flac_bitrate, _("Avg. bitrate: %.1f kb/s\nCompression ratio: %.1f%%"),
+					8.0 * (float)(_stat.st_size) / (1000.0 * (float)streaminfo.data.stream_info.total_samples / (float)streaminfo.data.stream_info.sample_rate),
+					100.0 * (float)_stat.st_size / (float)(streaminfo.data.stream_info.bits_per_sample / 8 * streaminfo.data.stream_info.channels * streaminfo.data.stream_info.total_samples));
+	}
+}
+
+static void show_replaygain(void)
+{
+	/* known limitation: If only one of gain and peak is set, neither will be shown. This is true for
+	 * both track and album replaygain tags. Written so it will be easy to fix, with some trouble.  */
+
+	gtk_label_set_text(GTK_LABEL(replaygain_reference), "");
+	gtk_label_set_text(GTK_LABEL(replaygain_track_gain), "");
+	gtk_label_set_text(GTK_LABEL(replaygain_album_gain), "");
+	gtk_label_set_text(GTK_LABEL(replaygain_track_peak), "");
+	gtk_label_set_text(GTK_LABEL(replaygain_album_peak), "");
+
+	double reference, track_gain, track_peak, album_gain, album_peak;
+	FLAC__bool reference_set, track_gain_set, track_peak_set, album_gain_set, album_peak_set;
+
+	if(!FLAC_plugin__replaygain_get_from_file(
+		current_filename,
+		&reference, &reference_set,
+		&track_gain, &track_gain_set,
+		&album_gain, &album_gain_set,
+		&track_peak, &track_peak_set,
+		&album_peak, &album_peak_set
+	))
+		return;
+
+	if(reference_set)
+		  label_set_text(replaygain_reference, _("ReplayGain Reference Loudness: %2.1f dB"), reference);
+	if(track_gain_set)
+		  label_set_text(replaygain_track_gain, _("ReplayGain Track Gain: %+2.2f dB"), track_gain);
+	if(album_gain_set)
+		  label_set_text(replaygain_album_gain, _("ReplayGain Album Gain: %+2.2f dB"), album_gain);
+	if(track_peak_set)
+		  label_set_text(replaygain_track_peak, _("ReplayGain Track Peak: %1.8f"), track_peak);
+	if(album_peak_set)
+		  label_set_text(replaygain_album_peak, _("ReplayGain Album Peak: %1.8f"), album_peak);
+}
+
+void FLAC_XMMS__file_info_box(char *filename)
+{
+	uint32_t i;
+	gchar *title;
+
+	if (!window)
+	{
+		GtkWidget *vbox, *hbox, *left_vbox, *table;
+		GtkWidget *flac_frame, *flac_box;
+		GtkWidget *label, *filename_hbox;
+		GtkWidget *bbox, *save, *remove, *cancel;
+
+		window = gtk_window_new(GTK_WINDOW_DIALOG);
+		gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
+		gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window);
+		gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+		vbox = gtk_vbox_new(FALSE, 10);
+		gtk_container_add(GTK_CONTAINER(window), vbox);
+
+		filename_hbox = gtk_hbox_new(FALSE, 5);
+		gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, FALSE, TRUE, 0);
+
+		label = gtk_label_new(_("Filename:"));
+		gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0);
+		filename_entry = gtk_entry_new();
+		gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE);
+		gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, TRUE, TRUE, 0);
+
+		hbox = gtk_hbox_new(FALSE, 10);
+		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
+
+		left_vbox = gtk_vbox_new(FALSE, 10);
+		gtk_box_pack_start(GTK_BOX(hbox), left_vbox, FALSE, FALSE, 0);
+
+		tag_frame = gtk_frame_new(_("Tag:"));
+		gtk_box_pack_start(GTK_BOX(left_vbox), tag_frame, FALSE, FALSE, 0);
+
+		table = gtk_table_new(5, 5, FALSE);
+		gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+		gtk_container_add(GTK_CONTAINER(tag_frame), table);
+
+		label = gtk_label_new(_("Title:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 5, 5);
+
+		title_entry = gtk_entry_new();
+		gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+		label = gtk_label_new(_("Artist:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 5, 5);
+
+		artist_entry = gtk_entry_new();
+		gtk_table_attach(GTK_TABLE(table), artist_entry, 1, 4, 1, 2, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+		label = gtk_label_new(_("Album:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 5, 5);
+
+		album_entry = gtk_entry_new();
+		gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+		label = gtk_label_new(_("Comment:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 5, 5);
+
+		comment_entry = gtk_entry_new();
+		gtk_table_attach(GTK_TABLE(table), comment_entry, 1, 4, 3, 4, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+		label = gtk_label_new(_("Date:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 5, 5);
+
+		date_entry = gtk_entry_new();
+		gtk_widget_set_usize(date_entry, 40, -1);
+		gtk_table_attach(GTK_TABLE(table), date_entry, 1, 2, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+		label = gtk_label_new(_("Track number:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5, GTK_FILL, GTK_FILL, 5, 5);
+
+		tracknum_entry = gtk_entry_new();
+		gtk_widget_set_usize(tracknum_entry, 40, -1);
+		gtk_table_attach(GTK_TABLE(table), tracknum_entry, 3, 4, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+		label = gtk_label_new(_("Genre:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 5, 5);
+
+		genre_combo = gtk_combo_new();
+		gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), TRUE);
+
+		if (!genre_list)
+		{
+			for (i = 0; i < sizeof(vorbis_genres) / sizeof(*vorbis_genres) ; i++)
+				genre_list = g_list_prepend(genre_list, (char *)vorbis_genres[i]);
+			genre_list = g_list_prepend(genre_list, "");
+			genre_list = g_list_sort(genre_list, (GCompareFunc)g_strcasecmp);
+		}
+		gtk_combo_set_popdown_strings(GTK_COMBO(genre_combo), genre_list);
+
+		gtk_table_attach(GTK_TABLE(table), genre_combo, 1, 4, 5, 6, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+		bbox = gtk_hbutton_box_new();
+		gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+		gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+		gtk_box_pack_start(GTK_BOX(left_vbox), bbox, FALSE, FALSE, 0);
+
+		save = gtk_button_new_with_label(_("Save"));
+		gtk_signal_connect(GTK_OBJECT(save), "clicked", GTK_SIGNAL_FUNC(save_tag), NULL);
+		GTK_WIDGET_SET_FLAGS(save, GTK_CAN_DEFAULT);
+		gtk_box_pack_start(GTK_BOX(bbox), save, TRUE, TRUE, 0);
+		gtk_widget_grab_default(save);
+
+		remove= gtk_button_new_with_label(_("Remove Tag"));
+		gtk_signal_connect(GTK_OBJECT(remove), "clicked", GTK_SIGNAL_FUNC(remove_tag), NULL);
+		GTK_WIDGET_SET_FLAGS(remove, GTK_CAN_DEFAULT);
+		gtk_box_pack_start(GTK_BOX(bbox), remove, TRUE, TRUE, 0);
+
+		cancel = gtk_button_new_with_label(_("Cancel"));
+		gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
+		GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+		gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+		flac_frame = gtk_frame_new(_("FLAC Info:"));
+		gtk_box_pack_start(GTK_BOX(hbox), flac_frame, FALSE, FALSE, 0);
+
+		flac_box = gtk_vbox_new(FALSE, 5);
+		gtk_container_add(GTK_CONTAINER(flac_frame), flac_box);
+		gtk_container_set_border_width(GTK_CONTAINER(flac_box), 10);
+		gtk_box_set_spacing(GTK_BOX(flac_box), 0);
+
+		flac_samplerate = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_samplerate), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_samplerate), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_samplerate, FALSE, FALSE, 0);
+
+		flac_channels = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_channels), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_channels), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_channels, FALSE, FALSE, 0);
+
+		flac_bits_per_sample = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_bits_per_sample), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_bits_per_sample), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_bits_per_sample, FALSE, FALSE, 0);
+
+		flac_blocksize = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_blocksize), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_blocksize), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_blocksize, FALSE, FALSE, 0);
+
+		flac_filesize = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_filesize), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_filesize), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_filesize, FALSE, FALSE, 0);
+
+		flac_samples = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_samples), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_samples), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_samples, FALSE, FALSE, 0);
+
+		flac_bitrate = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_bitrate), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_bitrate), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_bitrate, FALSE, FALSE, 0);
+
+		replaygain_reference = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_reference), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_reference), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_reference, FALSE, FALSE, 0);
+
+		replaygain_track_gain = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_track_gain), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_track_gain), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_gain, FALSE, FALSE, 0);
+
+		replaygain_album_gain = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_album_gain), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_album_gain), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_gain, FALSE, FALSE, 0);
+
+		replaygain_track_peak = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_track_peak), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_track_peak), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_peak, FALSE, FALSE, 0);
+
+		replaygain_album_peak = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_album_peak), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_album_peak), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_peak, FALSE, FALSE, 0);
+
+		gtk_widget_show_all(window);
+	}
+
+	if(current_filename)
+		g_free(current_filename);
+	if(!(current_filename = g_strdup(filename)))
+		return;
+
+	title = g_strdup_printf(_("File Info - %s"), g_basename(filename));
+	gtk_window_set_title(GTK_WINDOW(window), title);
+	g_free(title);
+
+	gtk_entry_set_text(GTK_ENTRY(filename_entry), filename);
+	gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1);
+
+	if(tags_)
+		FLAC_plugin__tags_destroy(&tags_);
+
+	FLAC_plugin__tags_get(current_filename, &tags_);
+
+	show_tag();
+	show_file_info();
+	show_replaygain();
+
+	gtk_widget_set_sensitive(tag_frame, TRUE);
+}
diff --git a/src/plugin_xmms/http.c b/src/plugin_xmms/http.c
new file mode 100644
index 0000000..161d1b3
--- /dev/null
+++ b/src/plugin_xmms/http.c
@@ -0,0 +1,899 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+/* modified for FLAC support by Steven Richman (2003) */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <glib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <pthread.h>
+
+#include <xmms/util.h>
+#include <xmms/plugin.h>
+
+#include "FLAC/format.h"
+#include "configure.h"
+#include "locale_hack.h"
+
+/* on FreeBSD we get socklen_t from <sys/socket.h> */
+#if (!defined HAVE_SOCKLEN_T) && !defined(__FreeBSD__)
+typedef uint32_t socklen_t;
+#endif
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z))
+#define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w))
+
+static gchar *icy_name = NULL;
+static gint icy_metaint = 0;
+
+extern InputPlugin flac_ip;
+
+/* Static udp channel functions */
+static int udp_establish_listener (gint *sock);
+static int udp_check_for_data(gint sock);
+
+static char *flac_http_get_title(char *url);
+
+static gboolean prebuffering, going, eof = FALSE;
+static gint sock, rd_index, wr_index, buffer_length, prebuffer_length;
+static guint64 buffer_read = 0;
+static gchar *buffer;
+static guint64 offset;
+static pthread_t thread;
+static GtkWidget *error_dialog = NULL;
+
+static FILE *output_file = NULL;
+
+#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
+
+/* Encode the string S of length LENGTH to base64 format and place it
+   to STORE.  STORE will be 0-terminated, and must point to a writable
+   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
+static void base64_encode (const gchar *s, gchar *store, gint length)
+{
+	/* Conversion table.  */
+	static gchar tbl[64] = {
+		'A','B','C','D','E','F','G','H',
+		'I','J','K','L','M','N','O','P',
+		'Q','R','S','T','U','V','W','X',
+		'Y','Z','a','b','c','d','e','f',
+		'g','h','i','j','k','l','m','n',
+		'o','p','q','r','s','t','u','v',
+		'w','x','y','z','0','1','2','3',
+		'4','5','6','7','8','9','+','/'
+	};
+	gint i;
+	guchar *p = (guchar *)store;
+
+	/* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
+	for (i = 0; i < length; i += 3)
+	{
+		*p++ = tbl[s[0] >> 2];
+		*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
+		*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
+		*p++ = tbl[s[2] & 0x3f];
+		s += 3;
+	}
+	/* Pad the result if necessary...  */
+	if (i == length + 1)
+		*(p - 1) = '=';
+	else if (i == length + 2)
+		*(p - 1) = *(p - 2) = '=';
+	/* ...and zero-terminate it.  */
+	*p = '\0';
+}
+
+/* Create the authentication header contents for the `Basic' scheme.
+   This is done by encoding the string `USER:PASS' in base64 and
+   prepending `HEADER: Basic ' to it.  */
+static gchar *basic_authentication_encode (const gchar *user, const gchar *passwd, const gchar *header)
+{
+	gchar *t1, *t2, *res;
+	gint len1 = strlen (user) + 1 + strlen (passwd);
+	gint len2 = BASE64_LENGTH (len1);
+
+	t1 = g_strdup_printf("%s:%s", user, passwd);
+	t2 = g_malloc0(len2 + 1);
+	base64_encode (t1, t2, len1);
+	res = g_strdup_printf("%s: Basic %s\r\n", header, t2);
+	g_free(t2);
+	g_free(t1);
+
+	return res;
+}
+
+static void parse_url(const gchar * url, gchar ** user, gchar ** pass, gchar ** host, int *port, gchar ** filename)
+{
+	gchar *h, *p, *pt, *f, *temp, *ptr;
+
+	temp = g_strdup(url);
+	ptr = temp;
+
+	if (!strncasecmp("http://", ptr, 7))
+		ptr += 7;
+	h = strchr(ptr, '@');
+	f = strchr(ptr, '/');
+	if (h != NULL && (!f || h < f))
+	{
+		*h = '\0';
+		p = strchr(ptr, ':');
+		if (p != NULL && p < h)
+		{
+			*p = '\0';
+			p++;
+			*pass = g_strdup(p);
+		}
+		else
+			*pass = NULL;
+		*user = g_strdup(ptr);
+		h++;
+		ptr = h;
+	}
+	else
+	{
+		*user = NULL;
+		*pass = NULL;
+		h = ptr;
+	}
+	pt = strchr(ptr, ':');
+	if (pt != NULL && (f == NULL || pt < f))
+	{
+		*pt = '\0';
+		*port = atoi(pt + 1);
+	}
+	else
+	{
+		if (f)
+			*f = '\0';
+		*port = 80;
+	}
+	*host = g_strdup(h);
+
+	if (f)
+		*filename = g_strdup(f + 1);
+	else
+		*filename = NULL;
+	g_free(temp);
+}
+
+void flac_http_close(void)
+{
+	going = FALSE;
+
+	pthread_join(thread, NULL);
+	g_free(icy_name);
+	icy_name = NULL;
+}
+
+
+static gint http_used(void)
+{
+	if (wr_index >= rd_index)
+		return wr_index - rd_index;
+	return buffer_length - (rd_index - wr_index);
+}
+
+static gint http_free(void)
+{
+	if (rd_index > wr_index)
+		return (rd_index - wr_index) - 1;
+	return (buffer_length - (wr_index - rd_index)) - 1;
+}
+
+static void http_wait_for_data(gint bytes)
+{
+	while ((prebuffering || http_used() < bytes) && !eof && going)
+		xmms_usleep(10000);
+}
+
+static void show_error_message(gchar *error)
+{
+	if(!error_dialog)
+	{
+		GDK_THREADS_ENTER();
+		error_dialog = xmms_show_message(_("Error"), error, _("Ok"), FALSE,
+						 NULL, NULL);
+		gtk_signal_connect(GTK_OBJECT(error_dialog),
+				   "destroy",
+				   GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+				   &error_dialog);
+		GDK_THREADS_LEAVE();
+	}
+}
+
+int flac_http_read(gpointer data, gint length)
+{
+	gint len, cnt, off = 0, meta_len, meta_off = 0, i;
+	gchar *meta_data, **tags, *temp, *title;
+	if (length > buffer_length) {
+		length = buffer_length;
+	}
+
+	http_wait_for_data(length);
+
+	if (!going)
+		return 0;
+	len = min(http_used(), length);
+
+	while (len && http_used())
+	{
+		if ((flac_cfg.stream.cast_title_streaming) && (icy_metaint > 0) && (buffer_read % icy_metaint) == 0 && (buffer_read > 0))
+		{
+			meta_len = *((guchar *) buffer + rd_index) * 16;
+			rd_index = (rd_index + 1) % buffer_length;
+			if (meta_len > 0)
+			{
+				http_wait_for_data(meta_len);
+				meta_data = g_malloc0(meta_len);
+				if (http_used() >= meta_len)
+				{
+					while (meta_len)
+					{
+						cnt = min(meta_len, buffer_length - rd_index);
+						memcpy(meta_data + meta_off, buffer + rd_index, cnt);
+						rd_index = (rd_index + cnt) % buffer_length;
+						meta_len -= cnt;
+						meta_off += cnt;
+					}
+					tags = g_strsplit(meta_data, "';", 0);
+
+					for (i = 0; tags[i]; i++)
+					{
+						if (!strncasecmp(tags[i], "StreamTitle=", 12))
+						{
+							temp = g_strdup(tags[i] + 13);
+							title = g_strdup_printf("%s (%s)", temp, icy_name);
+							set_track_info(title, -1);
+							g_free(title);
+							g_free(temp);
+						}
+
+					}
+					g_strfreev(tags);
+
+				}
+				g_free(meta_data);
+			}
+			if (!http_used())
+				http_wait_for_data(length - off);
+			cnt = min3(len, buffer_length - rd_index, http_used());
+		}
+		else if ((icy_metaint > 0) && (flac_cfg.stream.cast_title_streaming))
+			cnt = min4(len, buffer_length - rd_index, http_used(), icy_metaint - (gint) (buffer_read % icy_metaint));
+		else
+			cnt = min3(len, buffer_length - rd_index, http_used());
+		if (output_file)
+			fwrite(buffer + rd_index, 1, cnt, output_file);
+
+		memcpy((gchar *)data + off, buffer + rd_index, cnt);
+		rd_index = (rd_index + cnt) % buffer_length;
+		buffer_read += cnt;
+		len -= cnt;
+		off += cnt;
+	}
+	if (!off) {
+		fprintf(stderr, "returning zero\n");
+	}
+	return off;
+}
+
+static gboolean http_check_for_data(void)
+{
+
+	fd_set set;
+	struct timeval tv;
+	gint ret;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 20000;
+	FD_ZERO(&set);
+	FD_SET(sock, &set);
+	ret = select(sock + 1, &set, NULL, NULL, &tv);
+	if (ret > 0)
+		return TRUE;
+	return FALSE;
+}
+
+gint flac_http_read_line(gchar * buf, gint size)
+{
+	gint i = 0;
+
+	while (going && i < size - 1)
+	{
+		if (http_check_for_data())
+		{
+			if (read(sock, buf + i, 1) <= 0)
+				return -1;
+			if (buf[i] == '\n')
+				break;
+			if (buf[i] != '\r')
+				i++;
+		}
+	}
+	if (!going)
+		return -1;
+	buf[i] = '\0';
+	return i;
+}
+
+/* returns the file descriptor of the socket, or -1 on error */
+static int http_connect (gchar *url_, gboolean head, guint64 offset)
+{
+	gchar line[1024], *user, *pass, *host, *filename,
+	     *status, *url, *temp, *file;
+	gchar *chost;
+	gint cnt, error, port, cport;
+	socklen_t err_len;
+	gboolean redirect;
+	int udp_sock = 0;
+	fd_set set;
+	struct hostent *hp;
+	struct sockaddr_in address;
+	struct timeval tv;
+
+	url = g_strdup (url_);
+
+	do
+	{
+		redirect=FALSE;
+
+		g_strstrip(url);
+
+		parse_url(url, &user, &pass, &host, &port, &filename);
+
+		if ((!filename || !*filename) && url[strlen(url) - 1] != '/')
+			temp = g_strconcat(url, "/", NULL);
+		else
+			temp = g_strdup(url);
+		g_free(url);
+		url = temp;
+
+		chost = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_host : host;
+		cport = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_port : port;
+
+		sock = socket(AF_INET, SOCK_STREAM, 0);
+		fcntl(sock, F_SETFL, O_NONBLOCK);
+		address.sin_family = AF_INET;
+
+		status = g_strdup_printf(_("LOOKING UP %s"), chost);
+		flac_ip.set_info_text(status);
+		g_free(status);
+
+		if (!(hp = gethostbyname(chost)))
+		{
+			status = g_strdup_printf(_("Couldn't look up host %s"), chost);
+			show_error_message(status);
+			g_free(status);
+
+			flac_ip.set_info_text(NULL);
+			eof = TRUE;
+		}
+
+		if (!eof)
+		{
+			memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr));
+			address.sin_port = (gint) g_htons(cport);
+
+			status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport);
+			flac_ip.set_info_text(status);
+			g_free(status);
+			if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1)
+			{
+				if (errno != EINPROGRESS)
+				{
+					status = g_strdup_printf(_("Couldn't connect to host %s"), chost);
+					show_error_message(status);
+					g_free(status);
+
+					flac_ip.set_info_text(NULL);
+					eof = TRUE;
+				}
+			}
+			while (going)
+			{
+				tv.tv_sec = 0;
+				tv.tv_usec = 10000;
+				FD_ZERO(&set);
+				FD_SET(sock, &set);
+				if (select(sock + 1, NULL, &set, NULL, &tv) > 0)
+				{
+					err_len = sizeof (error);
+					getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len);
+					if (error)
+					{
+						status = g_strdup_printf(_("Couldn't connect to host %s"),
+									 chost);
+						show_error_message(status);
+						g_free(status);
+
+						flac_ip.set_info_text(NULL);
+						eof = TRUE;
+
+					}
+					break;
+				}
+			}
+			if (!eof)
+			{
+				gchar *auth = NULL, *proxy_auth = NULL;
+				gchar udpspace[30];
+				int udp_port;
+
+				if (flac_cfg.stream.use_udp_channel)
+				{
+					udp_port = udp_establish_listener (&udp_sock);
+					if (udp_port > 0)
+						flac_snprintf (udpspace, sizeof (udpspace), "x-audiocast-udpport: %d\r\n", udp_port);
+					else
+						udp_sock = 0;
+				}
+
+				if(user && pass)
+					auth = basic_authentication_encode(user, pass, "Authorization");
+
+				if (flac_cfg.stream.use_proxy)
+				{
+					file = g_strdup(url);
+					if(flac_cfg.stream.proxy_use_auth && flac_cfg.stream.proxy_user && flac_cfg.stream.proxy_pass)
+					{
+						proxy_auth = basic_authentication_encode(flac_cfg.stream.proxy_user,
+											 flac_cfg.stream.proxy_pass,
+											 "Proxy-Authorization");
+					}
+				}
+				else
+					file = g_strconcat("/", filename, NULL);
+
+				temp = g_strdup_printf("GET %s HTTP/1.0\r\n"
+						       "Host: %s\r\n"
+						       "User-Agent: %s/%s\r\n"
+						       "%s%s%s%s",
+						       file, host, "Reference FLAC Player", FLAC__VERSION_STRING,
+						       proxy_auth ? proxy_auth : "", auth ? auth : "",
+						       flac_cfg.stream.cast_title_streaming ?  "Icy-MetaData:1\r\n" : "",
+						       flac_cfg.stream.use_udp_channel ? udpspace : "");
+				if (offset && !head) {
+					gchar *temp_dead = temp;
+					temp = g_strdup_printf ("%sRange: %" PRIu64 "-\r\n", temp, offset);
+					fputs (temp, stderr);
+					g_free (temp_dead);
+				}
+
+				g_free(file);
+				if(proxy_auth)
+					g_free(proxy_auth);
+				if(auth)
+					g_free(auth);
+				write(sock, temp, strlen(temp));
+				write(sock, "\r\n", 2);
+				g_free(temp);
+				flac_ip.set_info_text(_("CONNECTED: WAITING FOR REPLY"));
+				while (going && !eof)
+				  {
+					if (http_check_for_data())
+					{
+						if (flac_http_read_line(line, 1024))
+						{
+							status = strchr(line, ' ');
+							if (status)
+							{
+								if (status[1] == '2')
+									break;
+								else if(status[1] == '3' && status[2] == '0' && status[3] == '2')
+								{
+									while(going)
+									{
+										if(http_check_for_data())
+										{
+											if((cnt = flac_http_read_line(line, 1024)) != -1)
+											{
+												if(!cnt)
+													break;
+												if(!strncmp(line, "Location:", 9))
+												{
+													g_free(url);
+													url = g_strdup(line+10);
+												}
+											}
+											else
+											{
+												eof=TRUE;
+												flac_ip.set_info_text(NULL);
+												break;
+											}
+										}
+									}
+									redirect=TRUE;
+									break;
+								}
+								else
+								{
+									status = g_strdup_printf(_("Couldn't connect to host %s\nServer reported: %s"), chost, status);
+									show_error_message(status);
+									g_free(status);
+									break;
+								}
+							}
+						}
+						else
+						{
+							eof = TRUE;
+							flac_ip.set_info_text(NULL);
+						}
+					}
+				}
+
+				while (going && !redirect)
+				{
+					if (http_check_for_data())
+					{
+						if ((cnt = flac_http_read_line(line, 1024)) != -1)
+						{
+							if (!cnt)
+								break;
+							if (!strncmp(line, "icy-name:", 9))
+								icy_name = g_strdup(line + 9);
+							else if (!strncmp(line, "x-audiocast-name:", 17))
+								icy_name = g_strdup(line + 17);
+							if (!strncmp(line, "icy-metaint:", 12))
+								icy_metaint = atoi(line + 12);
+							if (!strncmp(line, "x-audiocast-udpport:", 20)) {
+#ifndef NDEBUG
+								fprintf (stderr, "Server wants udp messages on port %d\n", atoi (line + 20));
+#endif
+								/*udp_serverport = atoi (line + 20);*/
+							}
+
+						}
+						else
+						{
+							eof = TRUE;
+							flac_ip.set_info_text(NULL);
+							break;
+						}
+					}
+				}
+			}
+		}
+
+		if(redirect)
+		{
+			if (output_file)
+			{
+				fclose(output_file);
+				output_file = NULL;
+			}
+			close(sock);
+		}
+
+		g_free(user);
+		g_free(pass);
+		g_free(host);
+		g_free(filename);
+	} while(redirect);
+
+	g_free(url);
+	return eof ? -1 : sock;
+}
+
+static void *http_buffer_loop(void *arg)
+{
+	gchar *status, *url, *temp, *file;
+	gint cnt, written;
+	int udp_sock = 0;
+
+	url = (gchar *) arg;
+	sock = http_connect (url, false, offset);
+
+	if (sock >= 0 && flac_cfg.stream.save_http_stream) {
+		gchar *output_name;
+		file = flac_http_get_title(url);
+		output_name = file;
+		if (!strncasecmp(output_name, "http://", 7))
+			output_name += 7;
+		temp = strrchr(output_name, '.');
+		if (temp && (!strcasecmp(temp, ".fla") || !strcasecmp(temp, ".flac")))
+			*temp = '\0';
+
+		while ((temp = strchr(output_name, '/')))
+			*temp = '_';
+		output_name = g_strdup_printf("%s/%s.flac", flac_cfg.stream.save_http_path, output_name);
+
+		g_free(file);
+
+		output_file = fopen(output_name, "wb");
+		g_free(output_name);
+	}
+
+	while (going)
+	{
+
+		if (!http_used() && !flac_ip.output->buffer_playing())
+			prebuffering = TRUE;
+		if (http_free() > 0 && !eof)
+		{
+			if (http_check_for_data())
+			{
+				cnt = min(http_free(), buffer_length - wr_index);
+				if (cnt > 1024)
+					cnt = 1024;
+				written = read(sock, buffer + wr_index, cnt);
+				if (written <= 0)
+				{
+					eof = TRUE;
+					if (prebuffering)
+					{
+						prebuffering = FALSE;
+
+						flac_ip.set_info_text(NULL);
+					}
+
+				}
+				else
+					wr_index = (wr_index + written) % buffer_length;
+			}
+
+			if (prebuffering)
+			{
+				if (http_used() > prebuffer_length)
+				{
+					prebuffering = FALSE;
+					flac_ip.set_info_text(NULL);
+				}
+				else
+				{
+					status = g_strdup_printf(_("PRE-BUFFERING: %dKB/%dKB"), http_used() / 1024, prebuffer_length / 1024);
+					flac_ip.set_info_text(status);
+					g_free(status);
+				}
+
+			}
+		}
+		else
+			xmms_usleep(10000);
+
+		if (flac_cfg.stream.use_udp_channel && udp_sock != 0)
+			if (udp_check_for_data(udp_sock) < 0)
+			{
+				close(udp_sock);
+				udp_sock = 0;
+			}
+	}
+	if (output_file)
+	{
+		fclose(output_file);
+		output_file = NULL;
+	}
+	if (sock >= 0) {
+		close(sock);
+	}
+	if (udp_sock != 0)
+		close(udp_sock);
+
+	g_free(buffer);
+	g_free(url);
+
+	pthread_exit(NULL);
+	return NULL; /* avoid compiler warning */
+}
+
+int flac_http_open(const gchar * _url, guint64 _offset)
+{
+	gchar *url;
+
+	url = g_strdup(_url);
+
+	rd_index = 0;
+	wr_index = 0;
+	buffer_length = flac_cfg.stream.http_buffer_size * 1024;
+	prebuffer_length = (buffer_length * flac_cfg.stream.http_prebuffer) / 100;
+	buffer_read = 0;
+	icy_metaint = 0;
+	prebuffering = TRUE;
+	going = TRUE;
+	eof = FALSE;
+	buffer = g_malloc(buffer_length);
+	offset = _offset;
+
+	pthread_create(&thread, NULL, http_buffer_loop, url);
+
+	return 0;
+}
+
+char *flac_http_get_title(char *url)
+{
+	if (icy_name)
+		return g_strdup(icy_name);
+	if (g_basename(url) && strlen(g_basename(url)) > 0)
+		return g_strdup(g_basename(url));
+	return g_strdup(url);
+}
+
+/* Start UDP Channel specific stuff */
+
+/* Find a good local udp port and bind udp_sock to it, return the port */
+static int udp_establish_listener(int *sock)
+{
+	struct sockaddr_in sin;
+	socklen_t sinlen = sizeof (struct sockaddr_in);
+
+#ifndef NDEBUG
+	fprintf (stderr,"Establishing udp listener\n");
+#endif
+
+	if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      "udp_establish_listener(): unable to create socket");
+		return -1;
+	}
+
+	memset(&sin, 0, sinlen);
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = g_htonl(INADDR_ANY);
+
+	if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0)
+	{
+		g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      "udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
+		close(*sock);
+		return -1;
+	}
+	if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0)
+	{
+		g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      "udp_establish_listener():  Failed to set flags: %s", strerror(errno));
+		close(*sock);
+		return -1;
+	}
+
+	memset(&sin, 0, sinlen);
+	if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0)
+	{
+		g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      "udp_establish_listener():  Failed to retrieve socket info: %s", strerror(errno));
+		close(*sock);
+		return -1;
+	}
+
+#ifndef NDEBUG
+	fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
+#endif
+
+	return g_ntohs(sin.sin_port);
+}
+
+static int udp_check_for_data(int sock)
+{
+	char buf[1025], **lines;
+	char *valptr;
+	gchar *title;
+	gint len, i;
+	struct sockaddr_in from;
+	socklen_t fromlen;
+
+	fromlen = sizeof(struct sockaddr_in);
+
+	if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0)
+	{
+		if (errno != EAGAIN)
+		{
+			g_log(NULL, G_LOG_LEVEL_CRITICAL,
+			      "udp_read_data(): Error reading from socket: %s", strerror(errno));
+			return -1;
+		}
+		return 0;
+	}
+	buf[len] = '\0';
+#ifndef NDEBUG
+	fprintf (stderr,"Received: [%s]\n", buf);
+#endif
+	lines = g_strsplit(buf, "\n", 0);
+	if (!lines)
+		return 0;
+
+	for (i = 0; lines[i]; i++)
+	{
+		while ((lines[i][strlen(lines[i]) - 1] == '\n') ||
+		       (lines[i][strlen(lines[i]) - 1] == '\r'))
+			lines[i][strlen(lines[i]) - 1] = '\0';
+
+		valptr = strchr(lines[i], ':');
+
+		if (!valptr)
+			continue;
+		else
+			valptr++;
+
+		g_strstrip(valptr);
+		if (!strlen(valptr))
+			continue;
+
+		if (strstr(lines[i], "x-audiocast-streamtitle") != NULL)
+		{
+			title = g_strdup_printf ("%s (%s)", valptr, icy_name);
+			if (going)
+				set_track_info(title, -1);
+			g_free (title);
+		}
+
+#if 0
+		else if (strstr(lines[i], "x-audiocast-streamlength") != NULL)
+		{
+			if (atoi(valptr) != -1)
+				set_track_info(NULL, atoi(valptr));
+		}
+#endif
+
+		else if (strstr(lines[i], "x-audiocast-streammsg") != NULL)
+		{
+			/* set_track_info(title, -1); */
+/*  			xmms_show_message(_("Message"), valptr, _("Ok"), */
+/*  					  FALSE, NULL, NULL); */
+			g_message("Stream_message: %s", valptr);
+		}
+
+#if 0
+		/* Use this to direct your webbrowser.. yeah right.. */
+		else if (strstr(lines[i], "x-audiocast-streamurl") != NULL)
+		{
+			if (lasturl && g_strcmp (valptr, lasturl))
+			{
+				c_message (stderr, "Song URL: %s\n", valptr);
+				g_free (lasturl);
+				lasturl = g_strdup (valptr);
+			}
+		}
+#endif
+		else if (strstr(lines[i], "x-audiocast-udpseqnr:") != NULL)
+		{
+			gchar obuf[60];
+			flac_snprintf(obuf, sizeof (obuf), "x-audiocast-ack: %ld \r\n", atol(valptr));
+			if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0)
+			{
+				g_log(NULL, G_LOG_LEVEL_WARNING,
+				      "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno));
+			}
+#ifndef NDEBUG
+			else
+				fprintf(stderr,"Sent ack: %s", obuf);
+			fprintf (stderr,"Remote: %s:%d\n", inet_ntoa(from.sin_addr), g_ntohs(from.sin_port));
+#endif
+		}
+	}
+	g_strfreev(lines);
+	return 0;
+}
diff --git a/src/plugin_xmms/http.h b/src/plugin_xmms/http.h
new file mode 100644
index 0000000..a78e162
--- /dev/null
+++ b/src/plugin_xmms/http.h
@@ -0,0 +1,26 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__PLUGIN_XMMS__HTTP_H
+#define FLAC__PLUGIN_XMMS__HTTP_H
+
+extern int flac_http_open(const gchar * url, guint64 offset);
+extern void flac_http_close(void);
+extern int flac_http_read(gpointer data, gint length);
+
+
+#endif
diff --git a/src/plugin_xmms/locale_hack.h b/src/plugin_xmms/locale_hack.h
new file mode 100644
index 0000000..5737319
--- /dev/null
+++ b/src/plugin_xmms/locale_hack.h
@@ -0,0 +1,56 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Based on:
+ * locale.h - 2000/05/05 13:10 Jerome Couderc
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ * Gettext support for EasyTAG
+ */
+
+
+#ifndef FLAC__PLUGIN_COMMON__LOCALE_HACK_H
+#define FLAC__PLUGIN_COMMON__LOCALE_HACK_H
+
+#include <locale.h>
+
+/*
+ * Standard gettext macros.
+ */
+#ifdef ENABLE_NLS
+#  include <libintl.h>
+#  define _(String) gettext (String)
+#  ifdef gettext_noop
+#    define N_(String) gettext_noop (String)
+#  else
+#    define N_(String) (String)
+#  endif
+#else
+#  define textdomain(String) (String)
+#  define gettext(String) (String)
+#  define dgettext(Domain,Message) (Message)
+#  define dcgettext(Domain,Message,Type) (Message)
+#  define bindtextdomain(Domain,Directory) (Domain)
+#  define _(String) (String)
+#  define N_(String) (String)
+#endif
+
+
+#endif
diff --git a/src/plugin_xmms/plugin.c b/src/plugin_xmms/plugin.c
new file mode 100644
index 0000000..94fbae5
--- /dev/null
+++ b/src/plugin_xmms/plugin.c
@@ -0,0 +1,688 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin.h"
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <xmms/plugin.h>
+#include <xmms/util.h>
+#include <xmms/configfile.h>
+#include <xmms/titlestring.h>
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "FLAC/all.h"
+#include "plugin_common/all.h"
+#include "share/grabbag.h"
+#include "share/replaygain_synthesis.h"
+#include "configure.h"
+#include "charset.h"
+#include "http.h"
+#include "tag.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+extern void FLAC_XMMS__file_info_box(char *filename);
+
+typedef struct {
+	FLAC__bool abort_flag;
+	FLAC__bool is_playing;
+	FLAC__bool is_http_source;
+	FLAC__bool eof;
+	FLAC__bool play_thread_open; /* if true, is_playing must also be true */
+	FLAC__uint64 total_samples;
+	uint32_t bits_per_sample;
+	uint32_t channels;
+	uint32_t sample_rate;
+	int length_in_msec; /* int (instead of FLAC__uint64) only because that's what XMMS uses; seeking won't work right if this maxes out */
+	gchar *title;
+	AFormat sample_format;
+	uint32_t sample_format_bytes_per_sample;
+	int seek_to_in_sec;
+	FLAC__bool has_replaygain;
+	double replay_scale;
+	DitherContext dither_context;
+} stream_data_struct;
+
+static void FLAC_XMMS__init(void);
+static int  FLAC_XMMS__is_our_file(char *filename);
+static void FLAC_XMMS__play_file(char *filename);
+static void FLAC_XMMS__stop(void);
+static void FLAC_XMMS__pause(short p);
+static void FLAC_XMMS__seek(int time);
+static int  FLAC_XMMS__get_time(void);
+static void FLAC_XMMS__cleanup(void);
+static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length);
+
+static void *play_loop_(void *arg);
+
+static FLAC__bool safe_decoder_init_(const char *filename, FLAC__StreamDecoder *decoder);
+static void safe_decoder_finish_(FLAC__StreamDecoder *decoder);
+static void safe_decoder_delete_(FLAC__StreamDecoder *decoder);
+
+static FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *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);
+
+InputPlugin flac_ip =
+{
+	NULL,
+	NULL,
+	"FLAC Player v" VERSION,
+	FLAC_XMMS__init,
+	FLAC_XMMS__aboutbox,
+	FLAC_XMMS__configure,
+	FLAC_XMMS__is_our_file,
+	NULL,
+	FLAC_XMMS__play_file,
+	FLAC_XMMS__stop,
+	FLAC_XMMS__pause,
+	FLAC_XMMS__seek,
+	NULL,
+	FLAC_XMMS__get_time,
+	NULL,
+	NULL,
+	FLAC_XMMS__cleanup,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	FLAC_XMMS__get_song_info,
+	FLAC_XMMS__file_info_box,
+	NULL
+};
+
+#define SAMPLES_PER_WRITE 512
+#define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8))
+static FLAC__byte sample_buffer_[SAMPLE_BUFFER_SIZE];
+static uint32_t sample_buffer_first_, sample_buffer_last_;
+
+static FLAC__StreamDecoder *decoder_ = 0;
+static stream_data_struct stream_data_;
+static pthread_t decode_thread_;
+static FLAC__bool audio_error_ = false;
+static FLAC__bool is_big_endian_host_;
+
+#define BITRATE_HIST_SEGMENT_MSEC 500
+/* 500ms * 50 = 25s should be enough */
+#define BITRATE_HIST_SIZE 50
+static uint32_t bitrate_history_[BITRATE_HIST_SIZE];
+
+
+FLAC_API InputPlugin *get_iplugin_info(void)
+{
+	flac_ip.description = g_strdup_printf("Reference FLAC Player v%s", FLAC__VERSION_STRING);
+	return &flac_ip;
+}
+
+void set_track_info(const char* title, int length_in_msec)
+{
+	if (stream_data_.is_playing) {
+		flac_ip.set_info((char*) title, length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels);
+	}
+}
+
+static gchar* homedir(void)
+{
+	gchar *result;
+	char *env_home = getenv("HOME");
+	if (env_home) {
+		result = g_strdup (env_home);
+	} else {
+		uid_t uid = getuid();
+		struct passwd *pwent;
+		do {
+			pwent = getpwent();
+		} while (pwent && pwent->pw_uid != uid);
+		result = pwent ? g_strdup (pwent->pw_dir) : NULL;
+		endpwent();
+	}
+	return result;
+}
+
+static FLAC__bool is_http_source(const char *source)
+{
+	return 0 == strncasecmp(source, "http://", 7);
+}
+
+void FLAC_XMMS__init(void)
+{
+	ConfigFile *cfg;
+	FLAC__uint32 test = 1;
+
+	is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
+
+	flac_cfg.title.tag_override = FALSE;
+	if (flac_cfg.title.tag_format)
+		g_free(flac_cfg.title.tag_format);
+	flac_cfg.title.convert_char_set = FALSE;
+
+	cfg = xmms_cfg_open_default_file();
+
+	/* title */
+
+	xmms_cfg_read_boolean(cfg, "flac", "title.tag_override", &flac_cfg.title.tag_override);
+
+	if(!xmms_cfg_read_string(cfg, "flac", "title.tag_format", &flac_cfg.title.tag_format))
+		flac_cfg.title.tag_format = g_strdup("%p - %t");
+
+	xmms_cfg_read_boolean(cfg, "flac", "title.convert_char_set", &flac_cfg.title.convert_char_set);
+
+	if(!xmms_cfg_read_string(cfg, "flac", "title.user_char_set", &flac_cfg.title.user_char_set))
+		flac_cfg.title.user_char_set = FLAC_plugin__charset_get_current();
+
+	/* replaygain */
+
+	xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.enable", &flac_cfg.output.replaygain.enable);
+
+	xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.album_mode", &flac_cfg.output.replaygain.album_mode);
+
+	if(!xmms_cfg_read_int(cfg, "flac", "output.replaygain.preamp", &flac_cfg.output.replaygain.preamp))
+		flac_cfg.output.replaygain.preamp = 0;
+
+	xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.hard_limit", &flac_cfg.output.replaygain.hard_limit);
+
+	xmms_cfg_read_boolean(cfg, "flac", "output.resolution.normal.dither_24_to_16", &flac_cfg.output.resolution.normal.dither_24_to_16);
+	xmms_cfg_read_boolean(cfg, "flac", "output.resolution.replaygain.dither", &flac_cfg.output.resolution.replaygain.dither);
+
+	if(!xmms_cfg_read_int(cfg, "flac", "output.resolution.replaygain.noise_shaping", &flac_cfg.output.resolution.replaygain.noise_shaping))
+		flac_cfg.output.resolution.replaygain.noise_shaping = 1;
+
+	if(!xmms_cfg_read_int(cfg, "flac", "output.resolution.replaygain.bps_out", &flac_cfg.output.resolution.replaygain.bps_out))
+		flac_cfg.output.resolution.replaygain.bps_out = 16;
+
+	/* stream */
+
+	xmms_cfg_read_int(cfg, "flac", "stream.http_buffer_size", &flac_cfg.stream.http_buffer_size);
+	xmms_cfg_read_int(cfg, "flac", "stream.http_prebuffer", &flac_cfg.stream.http_prebuffer);
+	xmms_cfg_read_boolean(cfg, "flac", "stream.use_proxy", &flac_cfg.stream.use_proxy);
+	if(flac_cfg.stream.proxy_host)
+		g_free(flac_cfg.stream.proxy_host);
+	if(!xmms_cfg_read_string(cfg, "flac", "stream.proxy_host", &flac_cfg.stream.proxy_host))
+		flac_cfg.stream.proxy_host = g_strdup("");
+	xmms_cfg_read_int(cfg, "flac", "stream.proxy_port", &flac_cfg.stream.proxy_port);
+	xmms_cfg_read_boolean(cfg, "flac", "stream.proxy_use_auth", &flac_cfg.stream.proxy_use_auth);
+	if(flac_cfg.stream.proxy_user)
+		g_free(flac_cfg.stream.proxy_user);
+	flac_cfg.stream.proxy_user = NULL;
+	xmms_cfg_read_string(cfg, "flac", "stream.proxy_user", &flac_cfg.stream.proxy_user);
+	if(flac_cfg.stream.proxy_pass)
+		g_free(flac_cfg.stream.proxy_pass);
+	flac_cfg.stream.proxy_pass = NULL;
+	xmms_cfg_read_string(cfg, "flac", "stream.proxy_pass", &flac_cfg.stream.proxy_pass);
+	xmms_cfg_read_boolean(cfg, "flac", "stream.save_http_stream", &flac_cfg.stream.save_http_stream);
+	if (flac_cfg.stream.save_http_path)
+		g_free (flac_cfg.stream.save_http_path);
+	if (!xmms_cfg_read_string(cfg, "flac", "stream.save_http_path", &flac_cfg.stream.save_http_path) || ! *flac_cfg.stream.save_http_path) {
+		if (flac_cfg.stream.save_http_path)
+			g_free (flac_cfg.stream.save_http_path);
+		flac_cfg.stream.save_http_path = homedir();
+	}
+	xmms_cfg_read_boolean(cfg, "flac", "stream.cast_title_streaming", &flac_cfg.stream.cast_title_streaming);
+	xmms_cfg_read_boolean(cfg, "flac", "stream.use_udp_channel", &flac_cfg.stream.use_udp_channel);
+
+	decoder_ = FLAC__stream_decoder_new();
+
+	xmms_cfg_free(cfg);
+}
+
+int FLAC_XMMS__is_our_file(char *filename)
+{
+	char *ext;
+
+	ext = strrchr(filename, '.');
+	if(ext)
+		if(!strcasecmp(ext, ".flac") || !strcasecmp(ext, ".fla"))
+			return 1;
+	return 0;
+}
+
+void FLAC_XMMS__play_file(char *filename)
+{
+	FILE *f;
+
+	sample_buffer_first_ = sample_buffer_last_ = 0;
+	audio_error_ = false;
+	stream_data_.abort_flag = false;
+	stream_data_.is_playing = false;
+	stream_data_.is_http_source = is_http_source(filename);
+	stream_data_.eof = false;
+	stream_data_.play_thread_open = false;
+	stream_data_.has_replaygain = false;
+
+	if(!is_http_source(filename)) {
+		if(0 == (f = fopen(filename, "r")))
+			return;
+		fclose(f);
+	}
+
+	if(decoder_ == 0)
+		return;
+
+	if(!safe_decoder_init_(filename, decoder_))
+		return;
+
+	if(stream_data_.has_replaygain && flac_cfg.output.replaygain.enable) {
+		if(flac_cfg.output.resolution.replaygain.bps_out == 8) {
+			stream_data_.sample_format = FMT_U8;
+			stream_data_.sample_format_bytes_per_sample = 1;
+		}
+		else if(flac_cfg.output.resolution.replaygain.bps_out == 16) {
+			stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE;
+			stream_data_.sample_format_bytes_per_sample = 2;
+		}
+		else {
+			/*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */
+			fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", flac_cfg.output.resolution.replaygain.bps_out);
+			safe_decoder_finish_(decoder_);
+			return;
+		}
+	}
+	else {
+		if(stream_data_.bits_per_sample == 8) {
+			stream_data_.sample_format = FMT_U8;
+			stream_data_.sample_format_bytes_per_sample = 1;
+		}
+		else if(stream_data_.bits_per_sample == 16 || (stream_data_.bits_per_sample == 24 && flac_cfg.output.resolution.normal.dither_24_to_16)) {
+			stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE;
+			stream_data_.sample_format_bytes_per_sample = 2;
+		}
+		else {
+			/*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */
+			fprintf(stderr, "libxmms-flac: can't handle %u bit output\n", stream_data_.bits_per_sample);
+			safe_decoder_finish_(decoder_);
+			return;
+		}
+	}
+	FLAC__replaygain_synthesis__init_dither_context(&stream_data_.dither_context, stream_data_.sample_format_bytes_per_sample * 8, flac_cfg.output.resolution.replaygain.noise_shaping);
+	stream_data_.is_playing = true;
+
+	if(flac_ip.output->open_audio(stream_data_.sample_format, stream_data_.sample_rate, stream_data_.channels) == 0) {
+		audio_error_ = true;
+		safe_decoder_finish_(decoder_);
+		return;
+	}
+
+	stream_data_.title = flac_format_song_title(filename);
+	flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels);
+
+	stream_data_.seek_to_in_sec = -1;
+	stream_data_.play_thread_open = true;
+	pthread_create(&decode_thread_, NULL, play_loop_, NULL);
+}
+
+void FLAC_XMMS__stop(void)
+{
+	if(stream_data_.is_playing) {
+		stream_data_.is_playing = false;
+		if(stream_data_.play_thread_open) {
+			stream_data_.play_thread_open = false;
+			pthread_join(decode_thread_, NULL);
+		}
+		flac_ip.output->close_audio();
+		safe_decoder_finish_(decoder_);
+	}
+}
+
+void FLAC_XMMS__pause(short p)
+{
+	flac_ip.output->pause(p);
+}
+
+void FLAC_XMMS__seek(int time)
+{
+	if(!stream_data_.is_http_source) {
+		stream_data_.seek_to_in_sec = time;
+		stream_data_.eof = false;
+
+		while(stream_data_.seek_to_in_sec != -1)
+			xmms_usleep(10000);
+	}
+}
+
+int FLAC_XMMS__get_time(void)
+{
+	if(audio_error_)
+		return -2;
+	if(!stream_data_.is_playing || (stream_data_.eof && !flac_ip.output->buffer_playing()))
+		return -1;
+	else
+		return flac_ip.output->output_time();
+}
+
+void FLAC_XMMS__cleanup(void)
+{
+	safe_decoder_delete_(decoder_);
+	decoder_ = 0;
+}
+
+void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec)
+{
+	FLAC__StreamMetadata streaminfo;
+
+	if(0 == filename)
+		filename = "";
+
+	if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
+		/* @@@ how to report the error? */
+		if(title) {
+			if (!is_http_source(filename)) {
+				static const char *errtitle = "Invalid FLAC File: ";
+				if(strlen(errtitle) + 1 + strlen(filename) + 1 + 1 < strlen(filename)) { /* overflow check */
+					*title = NULL;
+				}
+				else {
+					size_t len = strlen(errtitle) + 1 + strlen(filename) + 1 + 1;
+					*title = g_malloc(len);
+					flac_snprintf(*title, len, "%s\"%s\"", errtitle, filename);
+				}
+			} else {
+				*title = NULL;
+			}
+		}
+		if(length_in_msec)
+			*length_in_msec = -1;
+		return;
+	}
+
+	if(title) {
+		*title = flac_format_song_title(filename);
+	}
+	if(length_in_msec) {
+		FLAC__uint64 l = (FLAC__uint64)((double)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5);
+		if (l > INT_MAX)
+			l = INT_MAX;
+		*length_in_msec = (int)l;
+	}
+}
+
+/***********************************************************************
+ * local routines
+ **********************************************************************/
+
+void *play_loop_(void *arg)
+{
+	uint32_t written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1;
+	FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0;
+
+	(void)arg;
+
+	while(stream_data_.is_playing) {
+		if(!stream_data_.eof) {
+			while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) {
+				uint32_t s;
+
+				s = sample_buffer_last_ - sample_buffer_first_;
+				if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) {
+					stream_data_.eof = true;
+					break;
+				}
+				else if(!FLAC__stream_decoder_process_single(decoder_)) {
+					/*@@@ this should probably be a dialog */
+					fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n");
+					stream_data_.eof = true;
+					break;
+				}
+				blocksize = sample_buffer_last_ - sample_buffer_first_ - s;
+				decode_position_frame_last = decode_position_frame;
+				if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame))
+					decode_position_frame = 0;
+			}
+			if(sample_buffer_last_ - sample_buffer_first_ > 0) {
+				const uint32_t n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE);
+				int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample;
+				FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample;
+				uint32_t written_time, bh_index_w;
+				FLAC__uint64 decode_position;
+
+				sample_buffer_first_ += n;
+				flac_ip.add_vis_pcm(flac_ip.output->written_time(), stream_data_.sample_format, stream_data_.channels, bytes, sample_buffer_start);
+				while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1)
+					xmms_usleep(10000);
+				if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1)
+					flac_ip.output->write_audio(sample_buffer_start, bytes);
+
+				/* compute current bitrate */
+
+				written_time = flac_ip.output->written_time();
+				bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+				if(bh_index_w != bh_index_last_w) {
+					bh_index_last_w = bh_index_w;
+					decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize;
+					bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] =
+						decode_position > decode_position_last && written_time > written_time_last ?
+							8000 * (decode_position - decode_position_last) / (written_time - written_time_last) :
+							stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample;
+					decode_position_last = decode_position;
+					written_time_last = written_time;
+				}
+			}
+			else {
+				stream_data_.eof = true;
+				xmms_usleep(10000);
+			}
+		}
+		else
+			xmms_usleep(10000);
+		if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) {
+			const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec;
+			FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples);
+			if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples)
+				target_sample = stream_data_.total_samples - 1;
+			if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) {
+				flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000);
+				bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+				if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame))
+					decode_position_frame = 0;
+				stream_data_.eof = false;
+				sample_buffer_first_ = sample_buffer_last_ = 0;
+			}
+			else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) {
+				/*@@@ this should probably be a dialog */
+				fprintf(stderr, "libxmms-flac: SEEK ERROR\n");
+				FLAC__stream_decoder_flush(decoder_);
+				stream_data_.eof = false;
+				sample_buffer_first_ = sample_buffer_last_ = 0;
+			}
+			stream_data_.seek_to_in_sec = -1;
+		}
+		else {
+			/* display the right bitrate from history */
+			uint32_t bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+			if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) {
+				bh_index_last_o = bh_index_o;
+				flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels);
+			}
+		}
+	}
+
+	safe_decoder_finish_(decoder_);
+
+	/* are these two calls necessary? */
+	flac_ip.output->buffer_free();
+	flac_ip.output->buffer_free();
+
+	g_free(stream_data_.title);
+
+	pthread_exit(NULL);
+	return 0; /* to silence the compiler warning about not returning a value */
+}
+
+FLAC__bool safe_decoder_init_(const char *filename, FLAC__StreamDecoder *decoder)
+{
+	if(decoder == 0)
+		return false;
+
+	safe_decoder_finish_(decoder);
+
+	FLAC__stream_decoder_set_md5_checking(decoder, false);
+	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	if(stream_data_.is_http_source) {
+		flac_http_open(filename, 0);
+		if(FLAC__stream_decoder_init_stream(decoder, http_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+			return false;
+	}
+	else {
+		if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+			return false;
+	}
+
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+		return false;
+
+	return true;
+}
+
+void safe_decoder_finish_(FLAC__StreamDecoder *decoder)
+{
+	if(decoder && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED)
+		(void)FLAC__stream_decoder_finish(decoder);
+	if(stream_data_.is_http_source)
+		flac_http_close();
+}
+
+void safe_decoder_delete_(FLAC__StreamDecoder *decoder)
+{
+	if(decoder) {
+		safe_decoder_finish_(decoder);
+		FLAC__stream_decoder_delete(decoder);
+	}
+}
+
+FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	(void)decoder;
+	(void)client_data;
+	*bytes = flac_http_read(buffer, *bytes);
+	return *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	stream_data_struct *stream_data = (stream_data_struct *)client_data;
+	const uint32_t channels = stream_data->channels, wide_samples = frame->header.blocksize;
+	const uint32_t bits_per_sample = stream_data->bits_per_sample;
+	FLAC__byte *sample_buffer_start;
+
+	(void)decoder;
+
+	if(stream_data->abort_flag)
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+	if((sample_buffer_last_ + wide_samples) > (SAMPLE_BUFFER_SIZE / (channels * stream_data->sample_format_bytes_per_sample))) {
+		memmove(sample_buffer_, sample_buffer_ + sample_buffer_first_ * channels * stream_data->sample_format_bytes_per_sample, (sample_buffer_last_ - sample_buffer_first_) * channels * stream_data->sample_format_bytes_per_sample);
+		sample_buffer_last_ -= sample_buffer_first_;
+		sample_buffer_first_ = 0;
+	}
+	sample_buffer_start = sample_buffer_ + sample_buffer_last_ * channels * stream_data->sample_format_bytes_per_sample;
+	if(stream_data->has_replaygain && flac_cfg.output.replaygain.enable) {
+		FLAC__replaygain_synthesis__apply_gain(
+				sample_buffer_start,
+				!is_big_endian_host_,
+				stream_data->sample_format_bytes_per_sample == 1, /* uint32_t_data_out */
+				buffer,
+				wide_samples,
+				channels,
+				bits_per_sample,
+				stream_data->sample_format_bytes_per_sample * 8,
+				stream_data->replay_scale,
+				flac_cfg.output.replaygain.hard_limit,
+				flac_cfg.output.resolution.replaygain.dither,
+				&stream_data->dither_context
+		);
+	}
+	else if(is_big_endian_host_) {
+		FLAC__plugin_common__pack_pcm_signed_big_endian(
+			sample_buffer_start,
+			buffer,
+			wide_samples,
+			channels,
+			bits_per_sample,
+			stream_data->sample_format_bytes_per_sample * 8
+		);
+	}
+	else {
+		FLAC__plugin_common__pack_pcm_signed_little_endian(
+			sample_buffer_start,
+			buffer,
+			wide_samples,
+			channels,
+			bits_per_sample,
+			stream_data->sample_format_bytes_per_sample * 8
+		);
+	}
+
+	sample_buffer_last_ += wide_samples;
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	stream_data_struct *stream_data = (stream_data_struct *)client_data;
+	(void)decoder;
+	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		stream_data->total_samples = metadata->data.stream_info.total_samples;
+		stream_data->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+		stream_data->channels = metadata->data.stream_info.channels;
+		stream_data->sample_rate = metadata->data.stream_info.sample_rate;
+		{
+			FLAC__uint64 l = (FLAC__uint64)((double)stream_data->total_samples / (double)stream_data->sample_rate * 1000.0 + 0.5);
+			if (l > INT_MAX)
+				l = INT_MAX;
+			stream_data->length_in_msec = (int)l;
+		}
+	}
+	else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+		double reference, gain, peak;
+		if(grabbag__replaygain_load_from_vorbiscomment(metadata, flac_cfg.output.replaygain.album_mode, /*strict=*/false, &reference, &gain, &peak)) {
+			stream_data->has_replaygain = true;
+			stream_data->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)flac_cfg.output.replaygain.preamp, /*prevent_clipping=*/!flac_cfg.output.replaygain.hard_limit);
+		}
+	}
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	stream_data_struct *stream_data = (stream_data_struct *)client_data;
+	(void)decoder;
+	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+		stream_data->abort_flag = true;
+}
diff --git a/src/plugin_xmms/plugin.h b/src/plugin_xmms/plugin.h
new file mode 100644
index 0000000..e3ba989
--- /dev/null
+++ b/src/plugin_xmms/plugin.h
@@ -0,0 +1,33 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__PLUGIN_XMMS__PLUGIN_H
+#define FLAC__PLUGIN_XMMS__PLUGIN_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined(__GNUC_STDC_INLINE__)
+#  define G_INLINE_FUNC extern inline __attribute__((gnu_inline))
+#endif
+
+void set_track_info(const char* title, int length_in_msec);
+
+#endif
diff --git a/src/plugin_xmms/tag.c b/src/plugin_xmms/tag.c
new file mode 100644
index 0000000..a8ecab4
--- /dev/null
+++ b/src/plugin_xmms/tag.c
@@ -0,0 +1,157 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Daisuke Shimamura
+ *
+ * Based on FLAC plugin.c and mpg123 plugin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <xmms/plugin.h>
+#include <xmms/util.h>
+#include <xmms/configfile.h>
+#include <xmms/titlestring.h>
+
+#include "FLAC/metadata.h"
+#include "plugin_common/tags.h"
+#include "charset.h"
+#include "configure.h"
+
+/*
+ * Function local__extname (filename)
+ *
+ *    Return pointer within filename to its extension, or NULL if
+ *    filename has no extension.
+ *
+ */
+static char *local__extname(const char *filename)
+{
+	char *ext = strrchr(filename, '.');
+
+	if (ext != NULL)
+		++ext;
+
+	return ext;
+}
+
+static char *local__getstr(char* str)
+{
+	if (str && strlen(str) > 0)
+		return str;
+	return NULL;
+}
+
+static int local__getnum(char* str)
+{
+	if (str && strlen(str) > 0)
+		return atoi(str);
+	return 0;
+}
+
+static char *local__getfield(const FLAC__StreamMetadata *tags, const char *name)
+{
+	if (0 != tags) {
+		const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name);
+		if (0 != utf8) {
+			if(flac_cfg.title.convert_char_set)
+				return convert_from_utf8_to_user(utf8);
+			else
+				return strdup(utf8);
+		}
+	}
+
+	return 0;
+}
+
+static void local__safe_free(char *s)
+{
+	if (0 != s)
+		free(s);
+}
+
+/*
+ * Function flac_format_song_title (tag, filename)
+ *
+ *    Create song title according to `tag' and/or `filename' and
+ *    return it.  The title must be subsequently freed using g_free().
+ *
+ */
+char *flac_format_song_title(char *filename)
+{
+	char *ret = NULL;
+	TitleInput *input = NULL;
+	FLAC__StreamMetadata *tags;
+	char *title, *artist, *performer, *album, *date, *tracknumber, *genre, *description;
+
+	FLAC_plugin__tags_get(filename, &tags);
+
+	title       = local__getfield(tags, "TITLE");
+	artist      = local__getfield(tags, "ARTIST");
+	performer   = local__getfield(tags, "PERFORMER");
+	album       = local__getfield(tags, "ALBUM");
+	date        = local__getfield(tags, "DATE");
+	tracknumber = local__getfield(tags, "TRACKNUMBER");
+	genre       = local__getfield(tags, "GENRE");
+	description = local__getfield(tags, "DESCRIPTION");
+
+	XMMS_NEW_TITLEINPUT(input);
+
+	input->performer = local__getstr(artist);
+	if(!input->performer)
+		input->performer = local__getstr(performer);
+	input->album_name = local__getstr(album);
+	input->track_name = local__getstr(title);
+	input->track_number = local__getnum(tracknumber);
+	input->year = local__getnum(date);
+	input->genre = local__getstr(genre);
+	input->comment = local__getstr(description);
+
+	input->file_name = g_basename(filename);
+	input->file_path = filename;
+	input->file_ext = local__extname(filename);
+	ret = xmms_get_titlestring(flac_cfg.title.tag_override ? flac_cfg.title.tag_format : xmms_get_gentitle_format(), input);
+	g_free(input);
+
+	if (!ret) {
+		/*
+		 * Format according to filename.
+		 */
+		ret = g_strdup(g_basename(filename));
+		if (local__extname(ret) != NULL)
+			*(local__extname(ret) - 1) = '\0';	/* removes period */
+	}
+
+	FLAC_plugin__tags_destroy(&tags);
+	local__safe_free(title);
+	local__safe_free(artist);
+	local__safe_free(performer);
+	local__safe_free(album);
+	local__safe_free(date);
+	local__safe_free(tracknumber);
+	local__safe_free(genre);
+	local__safe_free(description);
+	return ret;
+}
diff --git a/src/plugin_xmms/tag.h b/src/plugin_xmms/tag.h
new file mode 100644
index 0000000..cc5bccf
--- /dev/null
+++ b/src/plugin_xmms/tag.h
@@ -0,0 +1,24 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Daisuke Shimamura
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__PLUGIN_XMMS__TAG_H
+#define FLAC__PLUGIN_XMMS__TAG_H
+
+gchar *flac_format_song_title(gchar * filename);
+
+#endif
diff --git a/src/share/Makefile.am b/src/share/Makefile.am
new file mode 100644
index 0000000..9ee826b
--- /dev/null
+++ b/src/share/Makefile.am
@@ -0,0 +1,99 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+
+EXTRA_DIST = \
+	Makefile.lite \
+	README \
+	getopt/CMakeLists.txt \
+	getopt/Makefile.lite \
+	getopt/getopt_static.vcproj \
+	getopt/getopt_static.vcxproj \
+	getopt/getopt_static.vcxproj.filters \
+	grabbag/CMakeLists.txt \
+	grabbag/Makefile.lite \
+	grabbag/grabbag_static.vcproj \
+	grabbag/grabbag_static.vcxproj \
+	grabbag/grabbag_static.vcxproj.filters \
+	replaygain_analysis/CMakeLists.txt \
+	replaygain_analysis/Makefile.lite \
+	replaygain_analysis/replaygain_analysis_static.vcproj \
+	replaygain_analysis/replaygain_analysis_static.vcxproj \
+	replaygain_analysis/replaygain_analysis_static.vcxproj.filters \
+	replaygain_synthesis/CMakeLists.txt \
+	replaygain_synthesis/Makefile.lite \
+	replaygain_synthesis/replaygain_synthesis_static.vcproj \
+	replaygain_synthesis/replaygain_synthesis_static.vcxproj \
+	replaygain_synthesis/replaygain_synthesis_static.vcxproj.filters \
+	utf8/CMakeLists.txt \
+	utf8/Makefile.lite \
+	utf8/charmaps.h \
+	utf8/makemap.c \
+	utf8/charset_test.c \
+	utf8/utf8_static.vcproj \
+	utf8/utf8_static.vcxproj \
+	utf8/utf8_static.vcxproj.filters \
+	win_utf8_io/Makefile.lite \
+	win_utf8_io/win_utf8_io_static.vcproj \
+	win_utf8_io/win_utf8_io_static.vcxproj \
+	win_utf8_io/win_utf8_io_static.vcxproj.filters
+
+
+noinst_LTLIBRARIES = \
+	getopt/libgetopt.la \
+	grabbag/libgrabbag.la \
+	utf8/libutf8.la \
+	$(libwin_utf8_io) \
+	replaygain_analysis/libreplaygain_analysis.la \
+	replaygain_synthesis/libreplaygain_synthesis.la
+
+
+if OS_IS_WINDOWS
+win_utf8_io_libwin_utf8_io_la_SOURCES =	win_utf8_io/win_utf8_io.c
+libwin_utf8_io = win_utf8_io/libwin_utf8_io.la
+win_utf8_io_libwin_utf8_io_la_LIBADD = $(top_builddir)/src/libFLAC/libFLAC.la -lm
+else
+win_utf8_io_libwin_utf8_io_la_SOURCES =
+libwin_utf8_io =
+endif
+
+getopt_libgetopt_la_SOURCES = getopt/getopt.c getopt/getopt1.c
+
+grabbag_libgrabbag_la_SOURCES = \
+	grabbag/alloc.c \
+	grabbag/cuesheet.c \
+	grabbag/file.c \
+	grabbag/picture.c \
+	grabbag/replaygain.c \
+	grabbag/seektable.c \
+	grabbag/snprintf.c
+
+utf8_libutf8_la_SOURCES = \
+	utf8/charset.c \
+	utf8/charset.h \
+	utf8/iconvert.c \
+	utf8/iconvert.h \
+	utf8/utf8.c
+
+replaygain_analysis_libreplaygain_analysis_la_SOURCES = replaygain_analysis/replaygain_analysis.c
+
+replaygain_synthesis_libreplaygain_synthesis_la_CFLAGS = -I $(top_srcdir)/src/share/replaygain_synthesis/include
+replaygain_synthesis_libreplaygain_synthesis_la_SOURCES = replaygain_synthesis/replaygain_synthesis.c
diff --git a/src/share/Makefile.lite b/src/share/Makefile.lite
new file mode 100644
index 0000000..d577787
--- /dev/null
+++ b/src/share/Makefile.lite
@@ -0,0 +1,58 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+.PHONY: all getopt grabbag replaygain_analysis replaygain_synthesis utf8
+all: getopt replaygain_analysis grabbag replaygain_synthesis utf8
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+getopt:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+replaygain_analysis:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+grabbag:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+replaygain_synthesis:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+utf8:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+win_utf8_io:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+clean:
+	-(cd getopt ; $(MAKE) -f Makefile.lite clean)
+	-(cd grabbag ; $(MAKE) -f Makefile.lite clean)
+	-(cd replaygain_analysis ; $(MAKE) -f Makefile.lite clean)
+	-(cd replaygain_synthesis ; $(MAKE) -f Makefile.lite clean)
+	-(cd utf8 ; $(MAKE) -f Makefile.lite clean)
+	-(cd win_utf8_io ; $(MAKE) -f Makefile.lite clean)
diff --git a/src/share/README b/src/share/README
new file mode 100644
index 0000000..1d4fede
--- /dev/null
+++ b/src/share/README
@@ -0,0 +1,5 @@
+This directory contains several convenience libraries used by the rest of the
+tools and plugins.  Two of them (getopt and utf8) are shamelessly copied from
+vorbistools, one for manipulating UTF-8 strings (GPL) and one for implementing
+getopt (LGPL).  libFLAC does not link to either; the only FLAC tools that do
+are GPL'ed.
diff --git a/src/share/getopt/CMakeLists.txt b/src/share/getopt/CMakeLists.txt
new file mode 100644
index 0000000..83b530e
--- /dev/null
+++ b/src/share/getopt/CMakeLists.txt
@@ -0,0 +1,11 @@
+check_include_file("string.h" HAVE_STRING_H)
+
+find_package(Intl)
+
+add_library(getopt STATIC getopt.c getopt1.c)
+
+if(Intl_FOUND)
+    target_include_directories(getopt PRIVATE ${Intl_INCLUDE_DIRS})
+    target_link_libraries(getopt PUBLIC ${Intl_LIBRARIES})
+    target_compile_definitions(getopt PRIVATE HAVE_LIBINTL_H)
+endif()
diff --git a/src/share/getopt/Makefile.lite b/src/share/getopt/Makefile.lite
new file mode 100644
index 0000000..b4df6ec
--- /dev/null
+++ b/src/share/getopt/Makefile.lite
@@ -0,0 +1,16 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+LIB_NAME = libgetopt
+INCLUDES = -I$(topdir)/include
+
+SRCS_C = \
+	getopt.c \
+	getopt1.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/getopt/getopt.c b/src/share/getopt/getopt.c
new file mode 100644
index 0000000..23c119c
--- /dev/null
+++ b/src/share/getopt/getopt.c
@@ -0,0 +1,1062 @@
+/*
+	NOTE:
+	I cannot get the vanilla getopt code to work (i.e. compile only what
+	is needed and not duplicate symbols found in the standard library)
+	on all the platforms that FLAC supports.  In particular the gating
+	of code with the ELIDE_CODE #define is not accurate enough on systems
+	that are POSIX but not glibc.  If someone has a patch that works on
+	GNU/Linux, Darwin, AND Solaris please submit it on the project page:
+		https://sourceforge.net/p/flac/patches/
+
+	In the meantime I have munged the global symbols and removed gates
+	around code, while at the same time trying to touch the original as
+	little as possible.
+*/
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to drepper@gnu.org
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
+   	Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+# ifndef const
+#  define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#if 1
+/*[JEC] was:#ifndef ELIDE_CODE*/
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+# include <stdlib.h>
+# include <unistd.h>
+#endif	/* GNU C library.  */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+#  include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+# ifdef HAVE_LIBINTL_H
+#  include <libintl.h>
+#  define _(msgid)	gettext (msgid)
+# else
+#  define _(msgid)	(msgid)
+# endif
+#endif
+
+/* This version of `share__getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `share__getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "share/getopt.h"
+/*[JEC] was:#include "getopt.h"*/
+
+/* For communication from `share__getopt' to the caller.
+   When `share__getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *share__optarg = 0; /*[JEC] initialize to avoid being a 'Common' symbol */
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `share__getopt'.
+
+   On entry to `share__getopt', zero means this is the first call; initialize.
+
+   When `share__getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `share__optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int share__optind = 1;
+
+/* Formerly, initialization of getopt depended on share__optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+static int share____getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int share__opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int share__optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `share__getopt' to return -1 with `share__optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+# include <string.h>
+# define my_index	strchr
+#else
+
+#include <string.h>
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+#ifndef getenv
+extern char *getenv (const char * name);
+#endif
+
+static char *
+my_index (const char *str, int chr)
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+/* Defined in getopt_init.c  */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+  if (nonoption_flags_len > 0)						      \
+    {									      \
+      char __tmp = __getopt_nonoption_flags[ch1];			      \
+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];	      \
+      __getopt_nonoption_flags[ch2] = __tmp;				      \
+    }
+#else	/* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif	/* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,share__optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = share__optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+#ifdef _LIBC
+  /* First make sure the handling of the `__getopt_nonoption_flags'
+     string can work normally.  Our top argument must be in the range
+     of the string.  */
+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+    {
+      /* We must extend the array.  The user plays games with us and
+	 presents new arguments.  */
+      char *new_str = malloc (top + 1);
+      if (new_str == NULL)
+	nonoption_flags_len = nonoption_flags_max_len = 0;
+      else
+	{
+	  memset (__mempcpy (new_str, __getopt_nonoption_flags,
+			     nonoption_flags_max_len),
+		  '\0', top + 1 - nonoption_flags_max_len);
+	  nonoption_flags_max_len = top + 1;
+	  __getopt_nonoption_flags = new_str;
+	}
+    }
+#endif
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	      SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	      SWAP_FLAGS (bottom + i, middle + i);
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (share__optind - last_nonopt);
+  last_nonopt = share__optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined __STDC__ && __STDC__
+static const char *share___getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+share___getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = share__optind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      if (nonoption_flags_max_len == 0)
+	{
+	  if (__getopt_nonoption_flags == NULL
+	      || __getopt_nonoption_flags[0] == '\0')
+	    nonoption_flags_max_len = -1;
+	  else
+	    {
+	      const char *orig_str = __getopt_nonoption_flags;
+	      int len = nonoption_flags_max_len = strlen (orig_str);
+	      if (nonoption_flags_max_len < argc)
+		nonoption_flags_max_len = argc;
+	      __getopt_nonoption_flags =
+		malloc (nonoption_flags_max_len);
+	      if (__getopt_nonoption_flags == NULL)
+		nonoption_flags_max_len = -1;
+	      else
+		memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+			'\0', nonoption_flags_max_len - len);
+	    }
+	}
+      nonoption_flags_len = nonoption_flags_max_len;
+    }
+  else
+    nonoption_flags_len = 0;
+#else
+  (void)argc, (void)argv;
+#endif
+
+  return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `share__getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `share__getopt' finds another option character, it returns that character,
+   updating `share__optind' and `nextchar' so that the next call to `share__getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `share__getopt' returns -1.
+   Then `share__optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `share__opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `share__optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `share__optarg', otherwise `share__optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `share__getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct share__option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+share___getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct share__option *longopts;
+     int *longind;
+     int long_only;
+{
+  share__optarg = NULL;
+
+  if (share__optind == 0 || !share____getopt_initialized)
+    {
+      if (share__optind == 0)
+	share__optind = 1;	/* Don't scan ARGV[0], the program name.  */
+      optstring = share___getopt_initialize (argc, argv, optstring);
+      share____getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[share__optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+# define NONOPTION_P (argv[share__optind][0] != '-' || argv[share__optind][1] == '\0'	      \
+		      || (share__optind < nonoption_flags_len			      \
+			  && __getopt_nonoption_flags[share__optind] == '1'))
+#else
+# define NONOPTION_P (argv[share__optind][0] != '-' || argv[share__optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+	 moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > share__optind)
+	last_nonopt = share__optind;
+      if (first_nonopt > share__optind)
+	first_nonopt = share__optind;
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != share__optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != share__optind)
+	    first_nonopt = share__optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (share__optind < argc && NONOPTION_P)
+	    share__optind++;
+	  last_nonopt = share__optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (share__optind != argc && !strcmp (argv[share__optind], "--"))
+	{
+	  share__optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != share__optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = share__optind;
+	  last_nonopt = argc;
+
+	  share__optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (share__optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    share__optind = first_nonopt;
+	  return -1;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return -1;
+	  share__optarg = argv[share__optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[share__optind] + 1
+		  + (longopts != NULL && argv[share__optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[share__optind][1] == '-'
+	  || (long_only && (argv[share__optind][2] || !my_index (optstring, argv[share__optind][1])))))
+    {
+      char *nameend;
+      const struct share__option *p;
+      const struct share__option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if ((size_t) (nameend - nextchar) == strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (share__opterr)
+	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+		     argv[0], argv[share__optind]);
+	  nextchar += strlen (nextchar);
+	  share__optind++;
+	  share__optopt = 0;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  share__optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		share__optarg = nameend + 1;
+	      else
+		{
+		  if (share__opterr)
+		    {
+		      if (argv[share__optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+				 _("%s: option `--%s' doesn't allow an argument\n"),
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+				 _("%s: option `%c%s' doesn't allow an argument\n"),
+				 argv[0], argv[share__optind - 1][0], pfound->name);
+		    }
+
+		  nextchar += strlen (nextchar);
+
+		  share__optopt = pfound->val;
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (share__optind < argc)
+		share__optarg = argv[share__optind++];
+	      else
+		{
+		  if (share__opterr)
+		    fprintf (stderr,
+			   _("%s: option `%s' requires an argument\n"),
+			   argv[0], argv[share__optind - 1]);
+		  nextchar += strlen (nextchar);
+		  share__optopt = pfound->val;
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not share__getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[share__optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (share__opterr)
+	    {
+	      if (argv[share__optind][1] == '-')
+		/* --option */
+		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+			 argv[0], argv[share__optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  share__optind++;
+	  share__optopt = 0;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `share__optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++share__optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (share__opterr)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, _("%s: illegal option -- %c\n"),
+		       argv[0], c);
+	    else
+	      fprintf (stderr, _("%s: invalid option -- %c\n"),
+		       argv[0], c);
+	  }
+	share__optopt = c;
+	return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+	char *nameend;
+	const struct share__option *p;
+	const struct share__option *pfound = NULL;
+	int exact = 0;
+	int ambig = 0;
+	int indfound = 0;
+	int option_index;
+
+	/* This is an option that requires an argument.  */
+	if (*nextchar != '\0')
+	  {
+	    share__optarg = nextchar;
+	    /* If we end this ARGV-element by taking the rest as an arg,
+	       we must advance to the next element now.  */
+	    share__optind++;
+	  }
+	else if (share__optind == argc)
+	  {
+	    if (share__opterr)
+	      {
+		/* 1003.2 specifies the format of this message.  */
+		fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+			 argv[0], c);
+	      }
+	    share__optopt = c;
+	    if (optstring[0] == ':')
+	      c = ':';
+	    else
+	      c = '?';
+	    return c;
+	  }
+	else
+	  /* We already incremented `share__optind' once;
+	     increment it again when taking next ARGV-elt as argument.  */
+	  share__optarg = argv[share__optind++];
+
+	/* share__optarg is now the argument, see if it's in the
+	   table of longopts.  */
+
+	for (nextchar = nameend = share__optarg; *nameend && *nameend != '='; nameend++)
+	  /* Do nothing.  */ ;
+
+	/* Test all long options for either exact match
+	   or abbreviated matches.  */
+	for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	  if (!strncmp (p->name, nextchar, nameend - nextchar))
+	    {
+	      if ((size_t) (nameend - nextchar) == strlen (p->name))
+		{
+		  /* Exact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		  exact = 1;
+		  break;
+		}
+	      else if (pfound == NULL)
+		{
+		  /* First nonexact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		}
+	      else
+		/* Second or later nonexact match found.  */
+		ambig = 1;
+	    }
+	if (ambig && !exact)
+	  {
+	    if (share__opterr)
+	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+		       argv[0], argv[share__optind]);
+	    nextchar += strlen (nextchar);
+	    share__optind++;
+	    return '?';
+	  }
+	if (pfound != NULL)
+	  {
+	    option_index = indfound;
+	    if (*nameend)
+	      {
+		/* Don't test has_arg with >, because some C compilers don't
+		   allow it to be used on enums.  */
+		if (pfound->has_arg)
+		  share__optarg = nameend + 1;
+		else
+		  {
+		    if (share__opterr)
+		      fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+			       argv[0], pfound->name);
+
+		    nextchar += strlen (nextchar);
+		    return '?';
+		  }
+	      }
+	    else if (pfound->has_arg == 1)
+	      {
+		if (share__optind < argc)
+		  share__optarg = argv[share__optind++];
+		else
+		  {
+		    if (share__opterr)
+		      fprintf (stderr,
+			       _("%s: option `%s' requires an argument\n"),
+			       argv[0], argv[share__optind - 1]);
+		    nextchar += strlen (nextchar);
+		    return optstring[0] == ':' ? ':' : '?';
+		  }
+	      }
+	    nextchar += strlen (nextchar);
+	    if (longind != NULL)
+	      *longind = option_index;
+	    if (pfound->flag)
+	      {
+		*(pfound->flag) = pfound->val;
+		return 0;
+	      }
+	    return pfound->val;
+	  }
+	  nextchar = NULL;
+	  return 'W';	/* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		share__optarg = nextchar;
+		share__optind++;
+	      }
+	    else
+	      share__optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		share__optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		share__optind++;
+	      }
+	    else if (share__optind == argc)
+	      {
+		if (share__opterr)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr,
+			   _("%s: option requires an argument -- %c\n"),
+			   argv[0], c);
+		  }
+		share__optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `share__optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      share__optarg = argv[share__optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+share__getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return share___getopt_internal (argc, argv, optstring,
+			   (const struct share__option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif	/* Not ELIDE_CODE.  */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `share__getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = share__optind ? share__optind : 1;
+
+      c = share__getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", share__optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (share__optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (share__optind < argc)
+	printf ("%s ", argv[share__optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/src/share/getopt/getopt1.c b/src/share/getopt/getopt1.c
new file mode 100644
index 0000000..740e498
--- /dev/null
+++ b/src/share/getopt/getopt1.c
@@ -0,0 +1,204 @@
+/*
+	NOTE:
+	I cannot get the vanilla getopt code to work (i.e. compile only what
+	is needed and not duplicate symbols found in the standard library)
+	on all the platforms that FLAC supports.  In particular the gating
+	of code with the ELIDE_CODE #define is not accurate enough on systems
+	that are POSIX but not glibc.  If someone has a patch that works on
+	GNU/Linux, Darwin, AND Solaris please submit it on the project page:
+		https://sourceforge.net/p/flac/patches/
+
+	In the meantime I have munged the global symbols and removed gates
+	around code, while at the same time trying to touch the original as
+	little as possible.
+*/
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
+     Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "share/getopt.h"
+/*[JEC] was:#include "getopt.h"*/
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#if 1
+/*[JEC] was:#ifndef ELIDE_CODE*/
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+share__getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct share__option *long_options;
+     int *opt_index;
+{
+  return share___getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like share__getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+share__getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct share__option *long_options;
+     int *opt_index;
+{
+  return share___getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif	/* Not ELIDE_CODE.  */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = share__optind ? share__optind : 1;
+      int option_index = 0;
+      static struct share__option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = share__getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (share__optarg)
+	    printf (" with arg %s", share__optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", share__optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", share__optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (share__optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (share__optind < argc)
+	printf ("%s ", argv[share__optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/src/share/getopt/getopt_static.vcproj b/src/share/getopt/getopt_static.vcproj
new file mode 100644
index 0000000..efc4ba7
--- /dev/null
+++ b/src/share/getopt/getopt_static.vcproj
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="getopt_static"

+	ProjectGUID="{4cefbc80-c215-11db-8314-0800200c9a66}"

+	RootNamespace="getopt_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\getopt.c"

+				>

+			</File>

+			<File

+				RelativePath=".\getopt1.c"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\..\include\share\getopt.h"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/share/getopt/getopt_static.vcxproj b/src/share/getopt/getopt_static.vcxproj
new file mode 100644
index 0000000..d536824
--- /dev/null
+++ b/src/share/getopt/getopt_static.vcxproj
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc80-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>getopt_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="getopt.c" />

+    <ClCompile Include="getopt1.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\getopt.h" />

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/getopt/getopt_static.vcxproj.filters b/src/share/getopt/getopt_static.vcxproj.filters
new file mode 100644
index 0000000..b528a7d
--- /dev/null
+++ b/src/share/getopt/getopt_static.vcxproj.filters
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{98dc8c56-677d-4f5b-9c7e-031634c635f0}</UniqueIdentifier>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="getopt.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="getopt1.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\getopt.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/grabbag/CMakeLists.txt b/src/share/grabbag/CMakeLists.txt
new file mode 100644
index 0000000..203ae3f
--- /dev/null
+++ b/src/share/grabbag/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_library(grabbag STATIC
+    alloc.c
+    cuesheet.c
+    file.c
+    picture.c
+    replaygain.c
+    seektable.c
+    snprintf.c)
+target_link_libraries(grabbag PUBLIC
+    FLAC
+    replaygain_analysis)
+if(TARGET win_utf8_io)
+    target_link_libraries(grabbag PUBLIC win_utf8_io)
+endif()
diff --git a/src/share/grabbag/Makefile.lite b/src/share/grabbag/Makefile.lite
new file mode 100644
index 0000000..6c8ff6c
--- /dev/null
+++ b/src/share/grabbag/Makefile.lite
@@ -0,0 +1,30 @@
+#  grabbag - Convenience lib for various routines common to several tools
+
+#
+# GNU makefile
+#
+
+topdir = ../../..
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC.a $(libdir)/libreplaygain_analysis.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lFLAC -lreplaygain_analysis $(OGG_LIBS) -lm
+endif
+
+LIB_NAME = libgrabbag
+INCLUDES = -I$(topdir)/include
+
+SRCS_C = \
+	alloc.c \
+	cuesheet.c \
+	file.c \
+	picture.c \
+	replaygain.c \
+	seektable.c \
+	snprintf.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/grabbag/alloc.c b/src/share/grabbag/alloc.c
new file mode 100644
index 0000000..82a77b1
--- /dev/null
+++ b/src/share/grabbag/alloc.c
@@ -0,0 +1,48 @@
+/* alloc - Convenience routines for safely allocating memory
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  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 "share/alloc.h"
+
+void *safe_malloc_mul_2op_(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);
+}
diff --git a/src/share/grabbag/cuesheet.c b/src/share/grabbag/cuesheet.c
new file mode 100644
index 0000000..13784c2
--- /dev/null
+++ b/src/share/grabbag/cuesheet.c
@@ -0,0 +1,656 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "share/grabbag.h"
+#include "share/safe_str.h"
+
+uint32_t grabbag__cuesheet_msf_to_frame(uint32_t minutes, uint32_t seconds, uint32_t frames)
+{
+	return ((minutes * 60) + seconds) * 75 + frames;
+}
+
+void grabbag__cuesheet_frame_to_msf(uint32_t frame, uint32_t *minutes, uint32_t *seconds, uint32_t *frames)
+{
+	*frames = frame % 75;
+	frame /= 75;
+	*seconds = frame % 60;
+	frame /= 60;
+	*minutes = frame;
+}
+
+/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
+static int local__parse_int_(const char *s)
+{
+	int ret = 0;
+	char c;
+
+	if(*s == '\0')
+		return -1;
+
+	while('\0' != (c = *s++))
+		if(c >= '0' && c <= '9')
+			ret = ret * 10 + (c - '0');
+		else
+			return -1;
+
+	return ret;
+}
+
+/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
+static FLAC__int64 local__parse_int64_(const char *s)
+{
+	FLAC__int64 ret = 0;
+	char c;
+
+	if(*s == '\0')
+		return -1;
+
+	while('\0' != (c = *s++))
+		if(c >= '0' && c <= '9')
+			ret = ret * 10 + (c - '0');
+		else
+			return -1;
+
+	return ret;
+}
+
+/* accept minute:second:frame syntax of '[0-9]+:[0-9][0-9]?:[0-9][0-9]?', but max second of 59 and max frame of 74, e.g. 0:0:0, 123:45:67
+ * return sample number or <0 for error
+ * WATCHOUT: if sample rate is not evenly divisible by 75, the resulting sample number will be approximate
+ */
+static FLAC__int64 local__parse_msf_(const char *s, uint32_t sample_rate)
+{
+	FLAC__int64 ret, field;
+	char c;
+
+	c = *s++;
+	if(c >= '0' && c <= '9')
+		field = (c - '0');
+	else
+		return -1;
+	while(':' != (c = *s++)) {
+		if(c >= '0' && c <= '9')
+			field = field * 10 + (c - '0');
+		else
+			return -1;
+	}
+
+	ret = field * 60 * sample_rate;
+
+	c = *s++;
+	if(c >= '0' && c <= '9')
+		field = (c - '0');
+	else
+		return -1;
+	if(':' != (c = *s++)) {
+		if(c >= '0' && c <= '9') {
+			field = field * 10 + (c - '0');
+			c = *s++;
+			if(c != ':')
+				return -1;
+		}
+		else
+			return -1;
+	}
+
+	if(field >= 60)
+		return -1;
+
+	ret += field * sample_rate;
+
+	c = *s++;
+	if(c >= '0' && c <= '9')
+		field = (c - '0');
+	else
+		return -1;
+	if('\0' != (c = *s++)) {
+		if(c >= '0' && c <= '9') {
+			field = field * 10 + (c - '0');
+			c = *s++;
+		}
+		else
+			return -1;
+	}
+
+	if(c != '\0')
+		return -1;
+
+	if(field >= 75)
+		return -1;
+
+	ret += field * (sample_rate / 75);
+
+	return ret;
+}
+
+/* accept minute:second syntax of '[0-9]+:[0-9][0-9]?{,.[0-9]+}', but second < 60, e.g. 0:0.0, 3:5, 15:31.731
+ * return sample number or <0 for error
+ * WATCHOUT: depending on the sample rate, the resulting sample number may be approximate with fractional seconds
+ */
+static FLAC__int64 local__parse_ms_(const char *s, uint32_t sample_rate)
+{
+	FLAC__int64 ret, field;
+	double x;
+	char c, *end;
+
+	c = *s++;
+	if(c >= '0' && c <= '9')
+		field = (c - '0');
+	else
+		return -1;
+	while(':' != (c = *s++)) {
+		if(c >= '0' && c <= '9')
+			field = field * 10 + (c - '0');
+		else
+			return -1;
+	}
+
+	ret = field * 60 * sample_rate;
+
+	s++; /* skip the ':' */
+	if(strspn(s, "0123456789.") != strlen(s))
+		return -1;
+	x = strtod(s, &end);
+	if(*end || end == s)
+		return -1;
+	if(x < 0.0 || x >= 60.0)
+		return -1;
+
+	ret += (FLAC__int64)(x * sample_rate);
+
+	return ret;
+}
+
+static char *local__get_field_(char **s, FLAC__bool allow_quotes)
+{
+	FLAC__bool has_quote = false;
+	char *p;
+
+	FLAC__ASSERT(0 != s);
+
+	if(0 == *s)
+		return 0;
+
+	/* skip leading whitespace */
+	while(**s && 0 != strchr(" \t\r\n", **s))
+		(*s)++;
+
+	if(**s == 0) {
+		*s = 0;
+		return 0;
+	}
+
+	if(allow_quotes && (**s == '"')) {
+		has_quote = true;
+		(*s)++;
+		if(**s == 0) {
+			*s = 0;
+			return 0;
+		}
+	}
+
+	p = *s;
+
+	if(has_quote) {
+		*s = strchr(*s, '\"');
+		/* if there is no matching end quote, it's an error */
+		if(0 == *s)
+			p = *s = 0;
+		else {
+			**s = '\0';
+			(*s)++;
+		}
+	}
+	else {
+		while(**s && 0 == strchr(" \t\r\n", **s))
+			(*s)++;
+		if(**s) {
+			**s = '\0';
+			(*s)++;
+		}
+		else
+			*s = 0;
+	}
+
+	return p;
+}
+
+static FLAC__bool local__cuesheet_parse_(FILE *file, const char **error_message, uint32_t *last_line_read, FLAC__StreamMetadata *cuesheet, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+	char buffer[4096], *line, *field;
+	uint32_t forced_leadout_track_num = 0;
+	FLAC__uint64 forced_leadout_track_offset = 0;
+	int in_track_num = -1, in_index_num = -1;
+	FLAC__bool disc_has_catalog = false, track_has_flags = false, track_has_isrc = false, has_forced_leadout = false;
+	FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet;
+
+	FLAC__ASSERT(!is_cdda || sample_rate == 44100);
+	/* double protection */
+	if(is_cdda && sample_rate != 44100) {
+		*error_message = "CD-DA cuesheet only allowed with 44.1kHz sample rate";
+		return false;
+	}
+
+	cs->lead_in = is_cdda? 2 * 44100 /* The default lead-in size for CD-DA */ : 0;
+	cs->is_cd = is_cdda;
+
+	while(0 != fgets(buffer, sizeof(buffer), file)) {
+		(*last_line_read)++;
+		line = buffer;
+
+		{
+			size_t linelen = strlen(line);
+			if((linelen == sizeof(buffer)-1) && line[linelen-1] != '\n') {
+				*error_message = "line too long";
+				return false;
+			}
+		}
+
+		if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+			if(0 == FLAC__STRCASECMP(field, "CATALOG")) {
+				if(disc_has_catalog) {
+					*error_message = "found multiple CATALOG commands";
+					return false;
+				}
+				if(0 == (field = local__get_field_(&line, /*allow_quotes=*/true))) {
+					*error_message = "CATALOG is missing catalog number";
+					return false;
+				}
+				if(strlen(field) >= sizeof(cs->media_catalog_number)) {
+					*error_message = "CATALOG number is too long";
+					return false;
+				}
+				if(is_cdda && (strlen(field) != 13 || strspn(field, "0123456789") != 13)) {
+					*error_message = "CD-DA CATALOG number must be 13 decimal digits";
+					return false;
+				}
+				safe_strncpy(cs->media_catalog_number, field, sizeof(cs->media_catalog_number));
+				disc_has_catalog = true;
+			}
+			else if(0 == FLAC__STRCASECMP(field, "FLAGS")) {
+				if(track_has_flags) {
+					*error_message = "found multiple FLAGS commands";
+					return false;
+				}
+				if(in_track_num < 0 || in_index_num >= 0) {
+					*error_message = "FLAGS command must come after TRACK but before INDEX";
+					return false;
+				}
+				while(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+					if(0 == FLAC__STRCASECMP(field, "PRE"))
+						cs->tracks[cs->num_tracks-1].pre_emphasis = 1;
+				}
+				track_has_flags = true;
+			}
+			else if(0 == FLAC__STRCASECMP(field, "INDEX")) {
+				FLAC__int64 xx;
+				FLAC__StreamMetadata_CueSheet_Track *track = &cs->tracks[cs->num_tracks-1];
+				if(in_track_num < 0) {
+					*error_message = "found INDEX before any TRACK";
+					return false;
+				}
+				if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+					*error_message = "INDEX is missing index number";
+					return false;
+				}
+				in_index_num = local__parse_int_(field);
+				if(in_index_num < 0) {
+					*error_message = "INDEX has invalid index number";
+					return false;
+				}
+				FLAC__ASSERT(cs->num_tracks > 0);
+				if(track->num_indices == 0) {
+					/* it's the first index point of the track */
+					if(in_index_num > 1) {
+						*error_message = "first INDEX number of a TRACK must be 0 or 1";
+						return false;
+					}
+				}
+				else {
+					if(in_index_num != track->indices[track->num_indices-1].number + 1) {
+						*error_message = "INDEX numbers must be sequential";
+						return false;
+					}
+				}
+				if(is_cdda && in_index_num > 99) {
+					*error_message = "CD-DA INDEX number must be between 0 and 99, inclusive";
+					return false;
+				}
+				/*@@@ search for duplicate track number? */
+				if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+					*error_message = "INDEX is missing an offset after the index number";
+					return false;
+				}
+				/* first parse as minute:second:frame format */
+				xx = local__parse_msf_(field, sample_rate);
+				if(xx < 0) {
+					/* CD-DA must use only MM:SS:FF format */
+					if(is_cdda) {
+						*error_message = "illegal INDEX offset (not of the form MM:SS:FF)";
+						return false;
+					}
+					/* as an extension for non-CD-DA we allow MM:SS.SS or raw sample number */
+					xx = local__parse_ms_(field, sample_rate);
+					if(xx < 0) {
+						xx = local__parse_int64_(field);
+						if(xx < 0) {
+							*error_message = "illegal INDEX offset";
+							return false;
+						}
+					}
+				}
+				else if(sample_rate % 75 && xx) {
+                                        /* only sample zero is exact */
+					*error_message = "illegal INDEX offset (MM:SS:FF form not allowed if sample rate is not a multiple of 75)";
+					return false;
+				}
+				if(is_cdda && cs->num_tracks == 1 && cs->tracks[0].num_indices == 0 && xx != 0) {
+					*error_message = "first INDEX of first TRACK must have an offset of 00:00:00";
+					return false;
+				}
+				if(is_cdda && track->num_indices > 0 && (FLAC__uint64)xx <= track->indices[track->num_indices-1].offset) {
+					*error_message = "CD-DA INDEX offsets must increase in time";
+					return false;
+				}
+				/* fill in track offset if it's the first index of the track */
+				if(track->num_indices == 0)
+					track->offset = (FLAC__uint64)xx;
+				if(is_cdda && cs->num_tracks > 1) {
+					const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-2];
+					if((FLAC__uint64)xx <= prev->offset + prev->indices[prev->num_indices-1].offset) {
+						*error_message = "CD-DA INDEX offsets must increase in time";
+						return false;
+					}
+				}
+				if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, cs->num_tracks-1, track->num_indices)) {
+					*error_message = "memory allocation error";
+					return false;
+				}
+				track->indices[track->num_indices-1].offset = (FLAC__uint64)xx - track->offset;
+				track->indices[track->num_indices-1].number = in_index_num;
+			}
+			else if(0 == FLAC__STRCASECMP(field, "ISRC")) {
+				char *l, *r;
+				if(track_has_isrc) {
+					*error_message = "found multiple ISRC commands";
+					return false;
+				}
+				if(in_track_num < 0 || in_index_num >= 0) {
+					*error_message = "ISRC command must come after TRACK but before INDEX";
+					return false;
+				}
+				if(0 == (field = local__get_field_(&line, /*allow_quotes=*/true))) {
+					*error_message = "ISRC is missing ISRC number";
+					return false;
+				}
+				/* strip out dashes */
+				for(l = r = field; *r; r++) {
+					if(*r != '-')
+						*l++ = *r;
+				}
+				*l = '\0';
+				if(strlen(field) != 12 || strspn(field, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") < 5 || strspn(field+5, "1234567890") != 7) {
+					*error_message = "invalid ISRC number";
+					return false;
+				}
+				safe_strncpy(cs->tracks[cs->num_tracks-1].isrc, field, sizeof(cs->tracks[cs->num_tracks-1].isrc));
+				track_has_isrc = true;
+			}
+			else if(0 == FLAC__STRCASECMP(field, "TRACK")) {
+				if(cs->num_tracks > 0) {
+					const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
+					if(
+						prev->num_indices == 0 ||
+						(
+						 	is_cdda &&
+							(
+								(prev->num_indices == 1 && prev->indices[0].number != 1) ||
+								(prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
+							)
+						)
+					) {
+						*error_message = is_cdda?
+							"previous TRACK must specify at least one INDEX 01" :
+							"previous TRACK must specify at least one INDEX";
+						return false;
+					}
+				}
+				if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+					*error_message = "TRACK is missing track number";
+					return false;
+				}
+				in_track_num = local__parse_int_(field);
+				if(in_track_num < 0) {
+					*error_message = "TRACK has invalid track number";
+					return false;
+				}
+				if(in_track_num == 0) {
+					*error_message = "TRACK number must be greater than 0";
+					return false;
+				}
+				if(is_cdda) {
+					if(in_track_num > 99) {
+						*error_message = "CD-DA TRACK number must be between 1 and 99, inclusive";
+						return false;
+					}
+				}
+				else {
+					if(in_track_num == 255) {
+						*error_message = "TRACK number 255 is reserved for the lead-out";
+						return false;
+					}
+					else if(in_track_num > 255) {
+						*error_message = "TRACK number must be between 1 and 254, inclusive";
+						return false;
+					}
+				}
+				if(is_cdda && cs->num_tracks > 0 && in_track_num != cs->tracks[cs->num_tracks-1].number + 1) {
+					*error_message = "CD-DA TRACK numbers must be sequential";
+					return false;
+				}
+				/*@@@ search for duplicate track number? */
+				if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+					*error_message = "TRACK is missing a track type after the track number";
+					return false;
+				}
+				if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
+					*error_message = "memory allocation error";
+					return false;
+				}
+				cs->tracks[cs->num_tracks-1].number = in_track_num;
+				cs->tracks[cs->num_tracks-1].type = (0 == FLAC__STRCASECMP(field, "AUDIO"))? 0 : 1; /*@@@ should we be more strict with the value here? */
+				in_index_num = -1;
+				track_has_flags = false;
+				track_has_isrc = false;
+			}
+			else if(0 == FLAC__STRCASECMP(field, "REM")) {
+				if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+					if(0 == strcmp(field, "FLAC__lead-in")) {
+						FLAC__int64 xx;
+						if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+							*error_message = "FLAC__lead-in is missing offset";
+							return false;
+						}
+						xx = local__parse_int64_(field);
+						if(xx < 0) {
+							*error_message = "illegal FLAC__lead-in offset";
+							return false;
+						}
+						if(is_cdda && xx % 588 != 0) {
+							*error_message = "illegal CD-DA FLAC__lead-in offset, must be even multiple of 588 samples";
+							return false;
+						}
+						cs->lead_in = (FLAC__uint64)xx;
+					}
+					else if(0 == strcmp(field, "FLAC__lead-out")) {
+						int track_num;
+						FLAC__int64 offset;
+						if(has_forced_leadout) {
+							*error_message = "multiple FLAC__lead-out commands";
+							return false;
+						}
+						if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+							*error_message = "FLAC__lead-out is missing track number";
+							return false;
+						}
+						track_num = local__parse_int_(field);
+						if(track_num < 0) {
+							*error_message = "illegal FLAC__lead-out track number";
+							return false;
+						}
+						forced_leadout_track_num = (uint32_t)track_num;
+						/*@@@ search for duplicate track number? */
+						if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+							*error_message = "FLAC__lead-out is missing offset";
+							return false;
+						}
+						offset = local__parse_int64_(field);
+						if(offset < 0) {
+							*error_message = "illegal FLAC__lead-out offset";
+							return false;
+						}
+						forced_leadout_track_offset = (FLAC__uint64)offset;
+						if(forced_leadout_track_offset != lead_out_offset) {
+							*error_message = "FLAC__lead-out offset does not match end-of-stream offset";
+							return false;
+						}
+						has_forced_leadout = true;
+					}
+				}
+			}
+		}
+	}
+
+	if(cs->num_tracks == 0) {
+		*error_message = "there must be at least one TRACK command";
+		return false;
+	}
+	else {
+		const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
+		if(
+			prev->num_indices == 0 ||
+			(
+				is_cdda &&
+				(
+					(prev->num_indices == 1 && prev->indices[0].number != 1) ||
+					(prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
+				)
+			)
+		) {
+			*error_message = is_cdda?
+				"previous TRACK must specify at least one INDEX 01" :
+				"previous TRACK must specify at least one INDEX";
+			return false;
+		}
+	}
+
+	if(!has_forced_leadout) {
+		forced_leadout_track_num = is_cdda? 170 : 255;
+		forced_leadout_track_offset = lead_out_offset;
+	}
+	if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
+		*error_message = "memory allocation error";
+		return false;
+	}
+	cs->tracks[cs->num_tracks-1].number = forced_leadout_track_num;
+	cs->tracks[cs->num_tracks-1].offset = forced_leadout_track_offset;
+
+	if(!feof(file)) {
+		*error_message = "read error";
+		return false;
+	}
+	return true;
+}
+
+FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, uint32_t *last_line_read, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+	FLAC__StreamMetadata *cuesheet;
+
+	FLAC__ASSERT(0 != file);
+	FLAC__ASSERT(0 != error_message);
+	FLAC__ASSERT(0 != last_line_read);
+
+	*last_line_read = 0;
+	cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+
+	if(0 == cuesheet) {
+		*error_message = "memory allocation error";
+		return 0;
+	}
+
+	if(!local__cuesheet_parse_(file, error_message, last_line_read, cuesheet, sample_rate, is_cdda, lead_out_offset)) {
+		FLAC__metadata_object_delete(cuesheet);
+		return 0;
+	}
+
+	return cuesheet;
+}
+
+void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference)
+{
+	const FLAC__StreamMetadata_CueSheet *cs;
+	uint32_t track_num, index_num;
+
+	FLAC__ASSERT(0 != file);
+	FLAC__ASSERT(0 != cuesheet);
+	FLAC__ASSERT(cuesheet->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	cs = &cuesheet->data.cue_sheet;
+
+	if(*(cs->media_catalog_number))
+		fprintf(file, "CATALOG %s\n", cs->media_catalog_number);
+	fprintf(file, "FILE %s\n", file_reference);
+
+	for(track_num = 0; track_num < cs->num_tracks-1; track_num++) {
+		const FLAC__StreamMetadata_CueSheet_Track *track = cs->tracks + track_num;
+
+		fprintf(file, "  TRACK %02u %s\n", (uint32_t)track->number, track->type == 0? "AUDIO" : "DATA");
+
+		if(track->pre_emphasis)
+			fprintf(file, "    FLAGS PRE\n");
+		if(*(track->isrc))
+			fprintf(file, "    ISRC %s\n", track->isrc);
+
+		for(index_num = 0; index_num < track->num_indices; index_num++) {
+			const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + index_num;
+
+			fprintf(file, "    INDEX %02u ", (uint32_t)indx->number);
+			if(cs->is_cd) {
+				const uint32_t logical_frame = (uint32_t)((track->offset + indx->offset) / (44100 / 75));
+				uint32_t m, s, f;
+				grabbag__cuesheet_frame_to_msf(logical_frame, &m, &s, &f);
+				fprintf(file, "%02u:%02u:%02u\n", m, s, f);
+			}
+			else
+				fprintf(file, "%" PRIu64 "\n", (track->offset + indx->offset));
+		}
+	}
+
+	fprintf(file, "REM FLAC__lead-in %" PRIu64 "\n", cs->lead_in);
+	fprintf(file, "REM FLAC__lead-out %u %" PRIu64 "\n", (uint32_t)cs->tracks[track_num].number, cs->tracks[track_num].offset);
+}
diff --git a/src/share/grabbag/file.c b/src/share/grabbag/file.c
new file mode 100644
index 0000000..5f3bc4e
--- /dev/null
+++ b/src/share/grabbag/file.c
@@ -0,0 +1,193 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/utime.h> /* for utime() */
+#include <io.h> /* for chmod(), _setmode(), unlink() */
+#include <fcntl.h> /* for _O_BINARY */
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#endif
+#if defined __EMX__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#if defined _WIN32 && !defined __CYGWIN__
+#else
+#include <unistd.h> /* for unlink() */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strrchr() */
+#if defined _WIN32 && !defined __CYGWIN__
+// for GetFileInformationByHandle() etc
+#include <windows.h>
+#include <winbase.h>
+#endif
+#include "share/grabbag.h"
+#include "share/compat.h"
+
+
+void grabbag__file_copy_metadata(const char *srcpath, const char *destpath)
+{
+	struct flac_stat_s srcstat;
+
+	if(0 == flac_stat(srcpath, &srcstat)) {
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+		struct timespec srctime[2] = {};
+		srctime[0].tv_sec = srcstat.st_atime;
+		srctime[1].tv_sec = srcstat.st_mtime;
+#else
+		struct utimbuf srctime;
+		srctime.actime = srcstat.st_atime;
+		srctime.modtime = srcstat.st_mtime;
+#endif
+		(void)flac_chmod(destpath, srcstat.st_mode);
+		(void)flac_utime(destpath, &srctime);
+	}
+}
+
+FLAC__off_t grabbag__file_get_filesize(const char *srcpath)
+{
+	struct flac_stat_s srcstat;
+
+	if(0 == flac_stat(srcpath, &srcstat))
+		return srcstat.st_size;
+	else
+		return -1;
+}
+
+const char *grabbag__file_get_basename(const char *srcpath)
+{
+	const char *p;
+
+	p = strrchr(srcpath, '/');
+	if(0 == p) {
+		p = strrchr(srcpath, '\\');
+		if(0 == p)
+			return srcpath;
+	}
+	return ++p;
+}
+
+FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only)
+{
+	struct flac_stat_s stats;
+
+	if(0 == flac_stat(filename, &stats)) {
+#if !defined _MSC_VER && !defined __MINGW32__
+		if(read_only) {
+			stats.st_mode &= ~S_IWUSR;
+			stats.st_mode &= ~S_IWGRP;
+			stats.st_mode &= ~S_IWOTH;
+		}
+		else {
+			stats.st_mode |= S_IWUSR;
+		}
+#else
+		if(read_only)
+			stats.st_mode &= ~S_IWRITE;
+		else
+			stats.st_mode |= S_IWRITE;
+#endif
+		if(0 != flac_chmod(filename, stats.st_mode))
+			return false;
+	}
+	else
+		return false;
+
+	return true;
+}
+
+FLAC__bool grabbag__file_are_same(const char *f1, const char *f2)
+{
+#if defined _WIN32 && !defined __CYGWIN__
+	/* see
+	 *  http://www.hydrogenaudio.org/forums/index.php?showtopic=49439&pid=444300&st=0
+	 *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getfileinformationbyhandle.asp
+	 *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/by_handle_file_information_str.asp
+	 *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/createfile.asp
+	 * apparently both the files have to be open at the same time for the comparison to work
+	 */
+	FLAC__bool same = false;
+	BY_HANDLE_FILE_INFORMATION info1, info2;
+	HANDLE h1, h2;
+	BOOL ok = 1;
+	h1 = CreateFile_utf8(f1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	h2 = CreateFile_utf8(f2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if(h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE)
+		ok = 0;
+	ok &= GetFileInformationByHandle(h1, &info1);
+	ok &= GetFileInformationByHandle(h2, &info2);
+	if(ok)
+		same =
+			info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber &&
+			info1.nFileIndexHigh == info2.nFileIndexHigh &&
+			info1.nFileIndexLow == info2.nFileIndexLow
+		;
+	if(h1 != INVALID_HANDLE_VALUE)
+		CloseHandle(h1);
+	if(h2 != INVALID_HANDLE_VALUE)
+		CloseHandle(h2);
+	return same;
+#else
+	struct flac_stat_s s1, s2;
+	return f1 && f2 && flac_stat(f1, &s1) == 0 && flac_stat(f2, &s2) == 0 && s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev;
+#endif
+}
+
+FLAC__bool grabbag__file_remove_file(const char *filename)
+{
+	return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == flac_unlink(filename);
+}
+
+FILE *grabbag__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 __EMX__
+	setmode(fileno(stdin), O_BINARY);
+#endif
+
+	return stdin;
+}
+
+FILE *grabbag__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 __EMX__
+	setmode(fileno(stdout), O_BINARY);
+#endif
+
+	return stdout;
+}
diff --git a/src/share/grabbag/grabbag_static.vcproj b/src/share/grabbag/grabbag_static.vcproj
new file mode 100644
index 0000000..d9f5a8a
--- /dev/null
+++ b/src/share/grabbag/grabbag_static.vcproj
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="grabbag_static"

+	ProjectGUID="{4cefbc81-c215-11db-8314-0800200c9a66}"

+	RootNamespace="grabbag_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\alloc.c"

+				>

+			</File>

+			<File

+				RelativePath=".\cuesheet.c"

+				>

+			</File>

+			<File

+				RelativePath=".\file.c"

+				>

+			</File>

+			<File

+				RelativePath=".\picture.c"

+				>

+			</File>

+			<File

+				RelativePath=".\replaygain.c"

+				>

+			</File>

+			<File

+				RelativePath=".\seektable.c"

+				>

+			</File>

+			<File

+				RelativePath=".\snprintf.c"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\..\include\share\grabbag.h"

+				>

+			</File>

+			<Filter

+				Name="grabbag"

+				>

+				<File

+					RelativePath="..\..\..\include\share\grabbag\cuesheet.h"

+					>

+				</File>

+				<File

+					RelativePath="..\..\..\include\share\grabbag\file.h"

+					>

+				</File>

+				<File

+					RelativePath="..\..\..\include\share\grabbag\picture.h"

+					>

+				</File>

+				<File

+					RelativePath="..\..\..\include\share\grabbag\replaygain.h"

+					>

+				</File>

+				<File

+					RelativePath="..\..\..\include\share\grabbag\seektable.h"

+					>

+				</File>

+			</Filter>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/share/grabbag/grabbag_static.vcxproj b/src/share/grabbag/grabbag_static.vcxproj
new file mode 100644
index 0000000..8ae6a28
--- /dev/null
+++ b/src/share/grabbag/grabbag_static.vcxproj
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc81-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>grabbag_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="alloc.c" />

+    <ClCompile Include="cuesheet.c" />

+    <ClCompile Include="file.c" />

+    <ClCompile Include="picture.c" />

+    <ClCompile Include="replaygain.c" />

+    <ClCompile Include="seektable.c" />

+    <ClCompile Include="snprintf.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\grabbag.h" />

+    <ClInclude Include="..\..\..\include\share\grabbag\cuesheet.h" />

+    <ClInclude Include="..\..\..\include\share\grabbag\file.h" />

+    <ClInclude Include="..\..\..\include\share\grabbag\picture.h" />

+    <ClInclude Include="..\..\..\include\share\grabbag\replaygain.h" />

+    <ClInclude Include="..\..\..\include\share\grabbag\seektable.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\replaygain_analysis\replaygain_analysis_static.vcxproj">

+      <Project>{4cefbc89-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\win_utf8_io\win_utf8_io_static.vcxproj">

+      <Project>{4cefbe02-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/grabbag/grabbag_static.vcxproj.filters b/src/share/grabbag/grabbag_static.vcxproj.filters
new file mode 100644
index 0000000..421b6d5
--- /dev/null
+++ b/src/share/grabbag/grabbag_static.vcxproj.filters
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{d4e83ff0-6406-4b76-bd64-6192e6b8e47a}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="Public Header Files\grabbag">

+      <UniqueIdentifier>{82df5da8-3a2c-402e-a7cd-a88de1a7be91}</UniqueIdentifier>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="alloc.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="cuesheet.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="file.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="picture.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="replaygain.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="seektable.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="snprintf.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\grabbag.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\..\include\share\grabbag\cuesheet.h">

+      <Filter>Public Header Files\grabbag</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\..\include\share\grabbag\file.h">

+      <Filter>Public Header Files\grabbag</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\..\include\share\grabbag\picture.h">

+      <Filter>Public Header Files\grabbag</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\..\include\share\grabbag\replaygain.h">

+      <Filter>Public Header Files\grabbag</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\..\include\share\grabbag\seektable.h">

+      <Filter>Public Header Files\grabbag</Filter>

+    </ClInclude>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/grabbag/picture.c b/src/share/grabbag/picture.c
new file mode 100644
index 0000000..89d5cc9
--- /dev/null
+++ b/src/share/grabbag/picture.c
@@ -0,0 +1,508 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2006-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "FLAC/assert.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+#include "share/safe_str.h"
+
+/* slightly different that strndup(): this always copies 'size' bytes starting from s into a NUL-terminated string. */
+static char *local__strndup_(const char *s, size_t size)
+{
+	char *x = safe_malloc_add_2op_(size, /*+*/1);
+	if(x) {
+		memcpy(x, s, size);
+		x[size] = '\0';
+	}
+	return x;
+}
+
+static FLAC__bool local__parse_type_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
+{
+	size_t i;
+	FLAC__uint32 val = 0;
+
+	picture->type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+
+	if(len == 0)
+		return true; /* empty string implies default to 'front cover' */
+
+	for(i = 0; i < len; i++) {
+		if(s[i] >= '0' && s[i] <= '9')
+			val = 10*val + (FLAC__uint32)(s[i] - '0');
+		else
+			return false;
+	}
+
+	if(i == len)
+		picture->type = val;
+	else
+		return false;
+
+	return true;
+}
+
+static FLAC__bool local__parse_resolution_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
+{
+	int state = 0;
+	size_t i;
+	FLAC__uint32 val = 0;
+
+	picture->width = picture->height = picture->depth = picture->colors = 0;
+
+	if(len == 0)
+		return true; /* empty string implies client wants to get info from the file itself */
+
+	for(i = 0; i < len; i++) {
+		if(s[i] == 'x') {
+			if(state == 0)
+				picture->width = val;
+			else if(state == 1)
+				picture->height = val;
+			else
+				return false;
+			state++;
+			val = 0;
+		}
+		else if(s[i] == '/') {
+			if(state == 2)
+				picture->depth = val;
+			else
+				return false;
+			state++;
+			val = 0;
+		}
+		else if(s[i] >= '0' && s[i] <= '9')
+			val = 10*val + (FLAC__uint32)(s[i] - '0');
+		else
+			return false;
+	}
+
+	if(state < 2)
+		return false;
+	else if(state == 2)
+		picture->depth = val;
+	else if(state == 3)
+		picture->colors = val;
+	else
+		return false;
+	if(picture->depth < 32 && 1u<<picture->depth < picture->colors)
+		return false;
+
+	return true;
+}
+
+static FLAC__bool local__extract_mime_type_(FLAC__StreamMetadata *obj)
+{
+	if(obj->data.picture.data_length >= 8 && 0 == memcmp(obj->data.picture.data, "\x89PNG\x0d\x0a\x1a\x0a", 8))
+		return FLAC__metadata_object_picture_set_mime_type(obj, "image/png", /*copy=*/true);
+	else if(obj->data.picture.data_length >= 6 && (0 == memcmp(obj->data.picture.data, "GIF87a", 6) || 0 == memcmp(obj->data.picture.data, "GIF89a", 6)))
+		return FLAC__metadata_object_picture_set_mime_type(obj, "image/gif", /*copy=*/true);
+	else if(obj->data.picture.data_length >= 2 && 0 == memcmp(obj->data.picture.data, "\xff\xd8", 2))
+		return FLAC__metadata_object_picture_set_mime_type(obj, "image/jpeg", /*copy=*/true);
+	return false;
+}
+
+static FLAC__bool local__extract_resolution_color_info_(FLAC__StreamMetadata_Picture *picture)
+{
+	const FLAC__byte *data = picture->data;
+	FLAC__uint32 len = picture->data_length;
+
+	if(0 == strcmp(picture->mime_type, "image/png")) {
+		/* c.f. http://www.w3.org/TR/PNG/ */
+		FLAC__bool need_palette = false; /* if IHDR has color_type=3, we need to also read the PLTE chunk to get the #colors */
+		if(len < 8 || memcmp(data, "\x89PNG\x0d\x0a\x1a\x0a", 8))
+			return false;
+		/* try to find IHDR chunk */
+		data += 8;
+		len -= 8;
+		while(len > 12) { /* every PNG chunk must be at least 12 bytes long */
+			const FLAC__uint32 clen = (FLAC__uint32)data[0] << 24 | (FLAC__uint32)data[1] << 16 | (FLAC__uint32)data[2] << 8 | (FLAC__uint32)data[3];
+			if(0 == memcmp(data+4, "IHDR", 4) && clen == 13) {
+				uint32_t color_type = data[17];
+				picture->width = (FLAC__uint32)data[8] << 24 | (FLAC__uint32)data[9] << 16 | (FLAC__uint32)data[10] << 8 | (FLAC__uint32)data[11];
+				picture->height = (FLAC__uint32)data[12] << 24 | (FLAC__uint32)data[13] << 16 | (FLAC__uint32)data[14] << 8 | (FLAC__uint32)data[15];
+				if(color_type == 3) {
+					/* even though the bit depth for color_type==3 can be 1,2,4,or 8,
+					 * the spec in 11.2.2 of http://www.w3.org/TR/PNG/ says that the
+					 * sample depth is always 8
+					 */
+					picture->depth = 8 * 3u;
+					need_palette = true;
+					data += 12 + clen;
+					len -= 12 + clen;
+				}
+				else {
+					if(color_type == 0) /* greyscale, 1 sample per pixel */
+						picture->depth = (FLAC__uint32)data[16];
+					if(color_type == 2) /* truecolor, 3 samples per pixel */
+						picture->depth = (FLAC__uint32)data[16] * 3u;
+					if(color_type == 4) /* greyscale+alpha, 2 samples per pixel */
+						picture->depth = (FLAC__uint32)data[16] * 2u;
+					if(color_type == 6) /* truecolor+alpha, 4 samples per pixel */
+						picture->depth = (FLAC__uint32)data[16] * 4u;
+					picture->colors = 0;
+					return true;
+				}
+			}
+			else if(need_palette && 0 == memcmp(data+4, "PLTE", 4)) {
+				picture->colors = clen / 3u;
+				return true;
+			}
+			else if(clen + 12 > len)
+				return false;
+			else {
+				data += 12 + clen;
+				len -= 12 + clen;
+			}
+		}
+	}
+	else if(0 == strcmp(picture->mime_type, "image/jpeg")) {
+		/* c.f. http://www.w3.org/Graphics/JPEG/itu-t81.pdf and Q22 of http://www.faqs.org/faqs/jpeg-faq/part1/ */
+		if(len < 2 || memcmp(data, "\xff\xd8", 2))
+			return false;
+		data += 2;
+		len -= 2;
+		while(1) {
+			/* look for sync FF byte */
+			for( ; len > 0; data++, len--) {
+				if(*data == 0xff)
+					break;
+			}
+			if(len == 0)
+				return false;
+			/* eat any extra pad FF bytes before marker */
+			for( ; len > 0; data++, len--) {
+				if(*data != 0xff)
+					break;
+			}
+			if(len == 0)
+				return false;
+			/* if we hit SOS or EOI, bail */
+			if(*data == 0xda || *data == 0xd9)
+				return false;
+			/* looking for some SOFn */
+			else if(memchr("\xc0\xc1\xc2\xc3\xc5\xc6\xc7\xc9\xca\xcb\xcd\xce\xcf", *data, 13)) {
+				data++; len--; /* skip marker byte */
+				if(len < 2)
+					return false;
+				else {
+					const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1];
+					if(clen < 8 || len < clen)
+						return false;
+					picture->width = (FLAC__uint32)data[5] << 8 | (FLAC__uint32)data[6];
+					picture->height = (FLAC__uint32)data[3] << 8 | (FLAC__uint32)data[4];
+					picture->depth = (FLAC__uint32)data[2] * (FLAC__uint32)data[7];
+					picture->colors = 0;
+					return true;
+				}
+			}
+			/* else skip it */
+			else {
+				data++; len--; /* skip marker byte */
+				if(len < 2)
+					return false;
+				else {
+					const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1];
+					if(clen < 2 || len < clen)
+						return false;
+					data += clen;
+					len -= clen;
+				}
+			}
+		}
+	}
+	else if(0 == strcmp(picture->mime_type, "image/gif")) {
+		/* c.f. http://www.w3.org/Graphics/GIF/spec-gif89a.txt */
+		if(len < 14)
+			return false;
+		if(memcmp(data, "GIF87a", 6) && memcmp(data, "GIF89a", 6))
+			return false;
+#if 0
+		/* according to the GIF spec, even if the GCTF is 0, the low 3 bits should still tell the total # colors used */
+		if(data[10] & 0x80 == 0)
+			return false;
+#endif
+		picture->width = (FLAC__uint32)data[6] | ((FLAC__uint32)data[7] << 8);
+		picture->height = (FLAC__uint32)data[8] | ((FLAC__uint32)data[9] << 8);
+#if 0
+		/* this value doesn't seem to be reliable... */
+		picture->depth = (((FLAC__uint32)(data[10] & 0x70) >> 4) + 1) * 3u;
+#else
+		/* ...just pessimistically assume it's 24-bit color without scanning all the color tables */
+		picture->depth = 8u * 3u;
+#endif
+		picture->colors = 1u << ((FLAC__uint32)(data[10] & 0x07) + 1u);
+		return true;
+	}
+	return false;
+}
+
+static const char *error_messages[] = {
+	"memory allocation error",
+	"invalid picture specification",
+	"invalid picture specification: can't parse resolution/color part",
+	"unable to extract resolution and color info from URL, user must set explicitly",
+	"unable to extract resolution and color info from file, user must set explicitly",
+	"error opening picture file",
+	"error reading picture file",
+	"invalid picture type",
+	"unable to guess MIME type from file, user must set explicitly",
+	"type 1 icon must be a 32x32 pixel PNG",
+	"file not found", /* currently unused */
+	"file is too large"
+};
+
+static const char * read_file (const char * filepath, FLAC__StreamMetadata * obj)
+{
+	const FLAC__off_t size = grabbag__file_get_filesize(filepath);
+	FLAC__byte *buffer;
+	FILE *file;
+	const char *error_message=NULL;
+
+	if (size < 0)
+		return error_messages[5];
+
+	if (size >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) /* actual limit is less because of other fields in the PICTURE metadata block */
+		return error_messages[11];
+
+	if ((buffer = safe_malloc_(size)) == NULL)
+		return error_messages[0];
+
+	if ((file = flac_fopen(filepath, "rb")) == NULL) {
+		free(buffer);
+		return error_messages[5];
+	}
+
+	if (fread(buffer, 1, size, file) != (size_t) size) {
+		fclose(file);
+		free(buffer);
+		return error_messages[6];
+	}
+	fclose(file);
+
+	if (!FLAC__metadata_object_picture_set_data(obj, buffer, size, /*copy=*/false))
+		error_message = error_messages[6];
+	/* try to extract MIME type if user left it blank */
+	else if (*obj->data.picture.mime_type == '\0' && !local__extract_mime_type_(obj))
+		error_message = error_messages[8];
+	/* try to extract resolution/color info if user left it blank */
+	else if ((obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) && !local__extract_resolution_color_info_(&obj->data.picture))
+		error_message = error_messages[4];
+	/* check metadata block size */
+	else if (obj->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+		error_message = error_messages[11];
+
+	return error_message;
+}
+
+FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message)
+{
+	FLAC__StreamMetadata *obj;
+	int state = 0;
+
+	FLAC__ASSERT(0 != spec);
+	FLAC__ASSERT(0 != error_message);
+
+	/* double protection */
+	if(0 == spec)
+		return 0;
+	if(0 == error_message)
+		return 0;
+
+	*error_message = 0;
+
+	if(0 == (obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE))) {
+		*error_message = error_messages[0];
+		return obj;
+	}
+
+	if(strchr(spec, '|')) { /* full format */
+		const char *p;
+		char *q;
+		for(p = spec; *error_message==0 && *p; ) {
+			if(*p == '|') {
+				switch(state) {
+					case 0: /* type */
+						if(!local__parse_type_(spec, p-spec, &obj->data.picture))
+							*error_message = error_messages[7];
+						break;
+					case 1: /* mime type */
+						if(p-spec) { /* if blank, we'll try to guess later from the picture data */
+							if(0 == (q = local__strndup_(spec, p-spec)))
+								*error_message = error_messages[0];
+							else if(!FLAC__metadata_object_picture_set_mime_type(obj, q, /*copy=*/false))
+								*error_message = error_messages[0];
+						}
+						break;
+					case 2: /* description */
+						if(0 == (q = local__strndup_(spec, p-spec)))
+							*error_message = error_messages[0];
+						else if(!FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*)q, /*copy=*/false))
+							*error_message = error_messages[0];
+						break;
+					case 3: /* resolution/color (e.g. [300x300x16[/1234]] */
+						if(!local__parse_resolution_(spec, p-spec, &obj->data.picture))
+							*error_message = error_messages[2];
+						break;
+					default:
+						*error_message = error_messages[1];
+						break;
+				}
+				p++;
+				spec = p;
+				state++;
+			}
+			else
+				p++;
+		}
+	}
+	else { /* simple format, filename only, everything else guessed */
+		if(!local__parse_type_("", 0, &obj->data.picture)) /* use default picture type */
+			*error_message = error_messages[7];
+		/* leave MIME type to be filled in later */
+		/* leave description empty */
+		/* leave the rest to be filled in later: */
+		else if(!local__parse_resolution_("", 0, &obj->data.picture))
+			*error_message = error_messages[2];
+		else
+			state = 4;
+	}
+
+	/* parse filename, read file, try to extract resolution/color info if needed */
+	if(*error_message == 0) {
+		if(state != 4)
+			*error_message = error_messages[1];
+		else { /* 'spec' points to filename/URL */
+			if(0 == strcmp(obj->data.picture.mime_type, "-->")) { /* magic MIME type means URL */
+				if(!FLAC__metadata_object_picture_set_data(obj, (FLAC__byte*)spec, strlen(spec), /*copy=*/true))
+					*error_message = error_messages[0];
+				else if(obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0)
+					*error_message = error_messages[3];
+			}
+			else { /* regular picture file */
+				*error_message = read_file (spec, obj);
+			}
+		}
+	}
+
+	if(*error_message == 0) {
+		if(
+			obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD &&
+			(
+				(strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) ||
+				obj->data.picture.width != 32 ||
+				obj->data.picture.height != 32
+			)
+		)
+			*error_message = error_messages[9];
+	}
+
+	if(*error_message && obj) {
+		FLAC__metadata_object_delete(obj);
+		obj = 0;
+	}
+
+	return obj;
+}
+
+FLAC__StreamMetadata *grabbag__picture_from_specification(int type, const char *mime_type_in, const char * description,
+		const PictureResolution * res, const char * filepath, const char **error_message)
+{
+
+	FLAC__StreamMetadata *obj;
+	char mime_type [64] ;
+
+	if (error_message == 0)
+		return 0;
+
+	safe_strncpy(mime_type, mime_type_in, sizeof (mime_type));
+
+	*error_message = 0;
+
+	if ((obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)) == 0) {
+		*error_message = error_messages[0];
+		return obj;
+	}
+
+	/* Picture type if known. */
+	obj->data.picture.type = type >= 0 ? type : FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+
+	/* Mime type if known. */
+	if (mime_type_in && ! FLAC__metadata_object_picture_set_mime_type(obj, mime_type, /*copy=*/true)) {
+		*error_message = error_messages[0];
+		return obj;
+	}
+
+	/* Description if present. */
+	if (description && ! FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*) description, /*copy=*/true)) {
+		*error_message = error_messages[0];
+		return obj;
+	}
+
+	if (res == NULL) {
+		obj->data.picture.width = 0;
+		obj->data.picture.height = 0;
+		obj->data.picture.depth = 0;
+		obj->data.picture.colors = 0;
+	}
+	else {
+		obj->data.picture.width = res->width;
+		obj->data.picture.height = res->height;
+		obj->data.picture.depth = res->depth;
+		obj->data.picture.colors = res->colors;
+	}
+
+	if (strcmp(obj->data.picture.mime_type, "-->") == 0) { /* magic MIME type means URL */
+		if (!FLAC__metadata_object_picture_set_data(obj, (FLAC__byte*)filepath, strlen(filepath), /*copy=*/true))
+			*error_message = error_messages[0];
+		else if (obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0)
+			*error_message = error_messages[3];
+	}
+	else {
+		*error_message = read_file (filepath, obj);
+	}
+
+	if (*error_message == NULL) {
+		if (
+			obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD &&
+			(
+				(strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) ||
+				obj->data.picture.width != 32 ||
+				obj->data.picture.height != 32
+			)
+		)
+			*error_message = error_messages[9];
+	}
+
+	if (*error_message && obj) {
+		FLAC__metadata_object_delete(obj);
+		obj = 0;
+	}
+
+	return obj;
+}
diff --git a/src/share/grabbag/replaygain.c b/src/share/grabbag/replaygain.c
new file mode 100644
index 0000000..fb23a47
--- /dev/null
+++ b/src/share/grabbag/replaygain.c
@@ -0,0 +1,668 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for chmod() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "FLAC/stream_decoder.h"
+#include "share/grabbag.h"
+#include "share/replaygain_analysis.h"
+#include "share/safe_str.h"
+
+#ifdef local_min
+#undef local_min
+#endif
+#define local_min(a,b) ((a)<(b)?(a):(b))
+
+#ifdef local_max
+#undef local_max
+#endif
+#define local_max(a,b) ((a)>(b)?(a):(b))
+
+static const char *reference_format_ = "%s=%2.1f dB";
+static const char *gain_format_ = "%s=%+2.2f dB";
+static const char *peak_format_ = "%s=%1.8f";
+
+static double album_peak_, title_peak_;
+
+const uint32_t GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED = 190;
+/*
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 29 + 1 + 8 +
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12 +
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12
+*/
+
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS = (const FLAC__byte * const)"REPLAYGAIN_REFERENCE_LOUDNESS";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN = (const FLAC__byte * const)"REPLAYGAIN_TRACK_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK = (const FLAC__byte * const)"REPLAYGAIN_TRACK_PEAK";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_PEAK";
+
+
+static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+	return (0 == flac_stat(filename, stats));
+}
+
+static void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+
+	(void)flac_chmod(filename, stats->st_mode);
+}
+
+static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value)
+{
+	char buffer[256];
+	char *saved_locale;
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(0 != format);
+	FLAC__ASSERT(0 != name);
+
+	buffer[sizeof(buffer)-1] = '\0';
+	/*
+	 * We need to save the old locale and switch to "C" because the locale
+	 * influences the formatting of %f and we want it a certain way.
+	 */
+	saved_locale = strdup(setlocale(LC_ALL, 0));
+	if (0 == saved_locale)
+		return false;
+	setlocale(LC_ALL, "C");
+	flac_snprintf(buffer, sizeof(buffer), format, name, value);
+	setlocale(LC_ALL, saved_locale);
+	free(saved_locale);
+
+	entry.entry = (FLAC__byte *)buffer;
+	entry.length = strlen(buffer);
+
+	return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true);
+}
+
+FLAC__bool grabbag__replaygain_is_valid_sample_frequency(uint32_t sample_frequency)
+{
+	return ValidGainFrequency( sample_frequency );
+}
+
+FLAC__bool grabbag__replaygain_init(uint32_t sample_frequency)
+{
+	title_peak_ = album_peak_ = 0.0;
+	return InitGainAnalysis((long)sample_frequency) == INIT_GAIN_ANALYSIS_OK;
+}
+
+FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, uint32_t bps, uint32_t samples)
+{
+	/* using a small buffer improves data locality; we'd like it to fit easily in the dcache */
+	static flac_float_t lbuffer[2048], rbuffer[2048];
+	static const uint32_t nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]);
+	FLAC__int32 block_peak = 0, s;
+	uint32_t i, j;
+
+	FLAC__ASSERT(bps >= 4 && bps <= FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE);
+	FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4);
+	/*
+	 * We use abs() on a FLAC__int32 which is undefined for the most negative value.
+	 * If the reference codec ever handles 32bps we will have to write a special
+	 * case here.
+	 */
+	FLAC__ASSERT(FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE < 32);
+
+	if(bps == 16) {
+		if(is_stereo) {
+			j = 0;
+			while(samples > 0) {
+				const uint32_t n = local_min(samples, nbuffer);
+				for(i = 0; i < n; i++, j++) {
+					s = input[0][j];
+					lbuffer[i] = (flac_float_t)s;
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+
+					s = input[1][j];
+					rbuffer[i] = (flac_float_t)s;
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+				}
+				samples -= n;
+				if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
+					return false;
+			}
+		}
+		else {
+			j = 0;
+			while(samples > 0) {
+				const uint32_t n = local_min(samples, nbuffer);
+				for(i = 0; i < n; i++, j++) {
+					s = input[0][j];
+					lbuffer[i] = (flac_float_t)s;
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+				}
+				samples -= n;
+				if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
+					return false;
+			}
+		}
+	}
+	else { /* bps must be < 32 according to above assertion */
+		const double scale = (
+			(bps > 16)?
+				(double)1. / (double)(1u << (bps - 16)) :
+				(double)(1u << (16 - bps))
+		);
+
+		if(is_stereo) {
+			j = 0;
+			while(samples > 0) {
+				const uint32_t n = local_min(samples, nbuffer);
+				for(i = 0; i < n; i++, j++) {
+					s = input[0][j];
+					lbuffer[i] = (flac_float_t)(scale * (double)s);
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+
+					s = input[1][j];
+					rbuffer[i] = (flac_float_t)(scale * (double)s);
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+				}
+				samples -= n;
+				if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
+					return false;
+			}
+		}
+		else {
+			j = 0;
+			while(samples > 0) {
+				const uint32_t n = local_min(samples, nbuffer);
+				for(i = 0; i < n; i++, j++) {
+					s = input[0][j];
+					lbuffer[i] = (flac_float_t)(scale * (double)s);
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+				}
+				samples -= n;
+				if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
+					return false;
+			}
+		}
+	}
+
+	{
+		const double peak_scale = (double)(1u << (bps - 1));
+		double peak = (double)block_peak / peak_scale;
+		if(peak > title_peak_)
+			title_peak_ = peak;
+		if(peak > album_peak_)
+			album_peak_ = peak;
+	}
+
+	return true;
+}
+
+void grabbag__replaygain_get_album(float *gain, float *peak)
+{
+	*gain = (float)GetAlbumGain();
+	*peak = (float)album_peak_;
+	album_peak_ = 0.0;
+}
+
+void grabbag__replaygain_get_title(float *gain, float *peak)
+{
+	*gain = (float)GetTitleGain();
+	*peak = (float)title_peak_;
+	title_peak_ = 0.0;
+}
+
+
+typedef struct {
+	uint32_t channels;
+	uint32_t bits_per_sample;
+	uint32_t sample_rate;
+	FLAC__bool error;
+} DecoderInstance;
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	DecoderInstance *instance = (DecoderInstance*)client_data;
+	const uint32_t bits_per_sample = frame->header.bits_per_sample;
+	const uint32_t channels = frame->header.channels;
+	const uint32_t sample_rate = frame->header.sample_rate;
+	const uint32_t samples = frame->header.blocksize;
+
+	(void)decoder;
+
+	if(
+		!instance->error &&
+		(channels == 2 || channels == 1) &&
+		bits_per_sample == instance->bits_per_sample &&
+		channels == instance->channels &&
+		sample_rate == instance->sample_rate
+	) {
+		instance->error = !grabbag__replaygain_analyze(buffer, channels==2, bits_per_sample, samples);
+	}
+	else {
+		instance->error = true;
+	}
+
+	if(!instance->error)
+		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+	else
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	DecoderInstance *instance = (DecoderInstance*)client_data;
+
+	(void)decoder;
+
+	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		instance->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+		instance->channels = metadata->data.stream_info.channels;
+		instance->sample_rate = metadata->data.stream_info.sample_rate;
+
+		if(instance->channels != 1 && instance->channels != 2) {
+			instance->error = true;
+			return;
+		}
+
+		if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) {
+			instance->error = true;
+			return;
+		}
+	}
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	DecoderInstance *instance = (DecoderInstance*)client_data;
+
+	(void)decoder, (void)status;
+
+	instance->error = true;
+}
+
+const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak)
+{
+	DecoderInstance instance;
+	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+
+	if(0 == decoder)
+		return "memory allocation error";
+
+	instance.error = false;
+
+	/* It does these three by default but lets be explicit: */
+	FLAC__stream_decoder_set_md5_checking(decoder, false);
+	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+
+	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &instance) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		FLAC__stream_decoder_delete(decoder);
+		return "initializing decoder";
+	}
+
+	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder) || instance.error) {
+		FLAC__stream_decoder_delete(decoder);
+		return "decoding file";
+	}
+
+	FLAC__stream_decoder_delete(decoder);
+
+	grabbag__replaygain_get_title(title_gain, title_peak);
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak)
+{
+	const char *error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak)))
+		return error;
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if(FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS) < 0)
+		return "memory allocation error";
+
+	if(!append_tag_(block, reference_format_, GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS, ReplayGainReferenceLoudness))
+		return "memory allocation error";
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak)
+{
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if(
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN) < 0 ||
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK) < 0
+	)
+		return "memory allocation error";
+
+	if(
+		!append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN, album_gain) ||
+		!append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK, album_peak)
+	)
+		return "memory allocation error";
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak)
+{
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if(
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN) < 0 ||
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK) < 0
+	)
+		return "memory allocation error";
+
+	if(
+		!append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN, title_gain) ||
+		!append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK, title_peak)
+	)
+		return "memory allocation error";
+
+	return 0;
+}
+
+static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block)
+{
+	FLAC__Metadata_Iterator *iterator;
+	const char *error;
+	FLAC__bool found_vc_block = false;
+
+	if(0 == (*chain = FLAC__metadata_chain_new()))
+		return "memory allocation error";
+
+	if(!FLAC__metadata_chain_read(*chain, filename)) {
+		error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
+		FLAC__metadata_chain_delete(*chain);
+		return error;
+	}
+
+	if(0 == (iterator = FLAC__metadata_iterator_new())) {
+		FLAC__metadata_chain_delete(*chain);
+		return "memory allocation error";
+	}
+
+	FLAC__metadata_iterator_init(iterator, *chain);
+
+	do {
+		*block = FLAC__metadata_iterator_get_block(iterator);
+		if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+			found_vc_block = true;
+	} while(!found_vc_block && FLAC__metadata_iterator_next(iterator));
+
+	if(!found_vc_block) {
+		/* create a new block */
+		*block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+		if(0 == *block) {
+			FLAC__metadata_chain_delete(*chain);
+			FLAC__metadata_iterator_delete(iterator);
+			return "memory allocation error";
+		}
+		while(FLAC__metadata_iterator_next(iterator))
+			;
+		if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) {
+			error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
+			FLAC__metadata_chain_delete(*chain);
+			FLAC__metadata_iterator_delete(iterator);
+			return error;
+		}
+		/* iterator is left pointing to new block */
+		FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block);
+	}
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	FLAC__ASSERT(0 != *block);
+	FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	return 0;
+}
+
+static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime)
+{
+	struct flac_stat_s stats;
+	const FLAC__bool have_stats = get_file_stats_(filename, &stats);
+
+	(void)grabbag__file_change_stats(filename, /*read_only=*/false);
+
+	FLAC__metadata_chain_sort_padding(chain);
+	if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) {
+		const char *error;
+		error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)];
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	FLAC__metadata_chain_delete(chain);
+
+	if(have_stats)
+		set_file_stats_(filename, &stats);
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block = NULL;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment(block, album_gain, album_peak, title_gain, title_peak))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block = NULL;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block = NULL;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block = NULL;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
+static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val)
+{
+	char s[32], *end;
+	const char *p, *q;
+	double v;
+
+	FLAC__ASSERT(0 != entry);
+	FLAC__ASSERT(0 != val);
+
+	p = (const char *)entry->entry;
+	q = strchr(p, '=');
+	if(0 == q)
+		return false;
+	q++;
+	safe_strncpy(s, q, local_min(sizeof(s), (size_t) (entry->length - (q-p))));
+
+	v = strtod(s, &end);
+	if(end == s)
+		return false;
+
+	*val = v;
+	return true;
+}
+
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak)
+{
+	int reference_offset, gain_offset, peak_offset;
+	char *saved_locale;
+	FLAC__bool res = true;
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(0 != reference);
+	FLAC__ASSERT(0 != gain);
+	FLAC__ASSERT(0 != peak);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	/* Default to current level until overridden by a detected tag; this
+	 * will always be true until we change replaygain_analysis.c
+	 */
+	*reference = ReplayGainReferenceLoudness;
+
+	/*
+	 * We need to save the old locale and switch to "C" because the locale
+	 * influences the behaviour of strtod and we want it a certain way.
+	 */
+	saved_locale = strdup(setlocale(LC_ALL, 0));
+	if (0 == saved_locale)
+		return false;
+	setlocale(LC_ALL, "C");
+
+	if(0 <= (reference_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS)))
+		(void)parse_double_(block->data.vorbis_comment.comments + reference_offset, reference);
+
+	if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN : GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN))))
+		res = false;
+	if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK : GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK))))
+		res = false;
+
+	if(res && !parse_double_(block->data.vorbis_comment.comments + gain_offset, gain))
+		res = false;
+	if(res && !parse_double_(block->data.vorbis_comment.comments + peak_offset, peak))
+		res = false;
+
+	setlocale(LC_ALL, saved_locale);
+	free(saved_locale);
+
+	/* something failed; retry with strict */
+	if (!res && !strict)
+		res = grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+
+	return res;
+}
+
+double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping)
+{
+	double scale;
+	FLAC__ASSERT(peak >= 0.0);
+ 	gain += preamp;
+	scale = (float) pow(10.0, gain * 0.05);
+	if(prevent_clipping && peak > 0.0) {
+		const double max_scale = (float)(1.0 / peak);
+		if(scale > max_scale)
+			scale = max_scale;
+	}
+	return scale;
+}
diff --git a/src/share/grabbag/seektable.c b/src/share/grabbag/seektable.c
new file mode 100644
index 0000000..2211e12
--- /dev/null
+++ b/src/share/grabbag/seektable.c
@@ -0,0 +1,106 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "FLAC/assert.h"
+#include <stdlib.h> /* for atoi() */
+#include <string.h>
+
+FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, uint32_t sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points)
+{
+	uint32_t i;
+	const char *pt;
+
+	FLAC__ASSERT(0 != spec);
+	FLAC__ASSERT(0 != seektable_template);
+	FLAC__ASSERT(seektable_template->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	if(0 != spec_has_real_points)
+		*spec_has_real_points = false;
+
+	for(pt = spec, i = 0; pt && *pt; i++) {
+		const char *q = strchr(pt, ';');
+		FLAC__ASSERT(0 != q);
+
+		if(q > pt) {
+			if(0 == strncmp(pt, "X;", 2)) { /* -S X */
+				if(!FLAC__metadata_object_seektable_template_append_placeholders(seektable_template, 1))
+					return false;
+			}
+			else if(q[-1] == 'x') { /* -S #x */
+				if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */
+					if(0 != spec_has_real_points)
+						*spec_has_real_points = true;
+					if(!only_explicit_placeholders) {
+						const int n = (uint32_t)atoi(pt);
+						if(n > 0)
+							if(!FLAC__metadata_object_seektable_template_append_spaced_points(seektable_template, (uint32_t)n, total_samples_to_encode))
+								return false;
+					}
+				}
+			}
+			else if(q[-1] == 's') { /* -S #s */
+				if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */
+					FLAC__ASSERT(sample_rate > 0);
+					if(0 != spec_has_real_points)
+						*spec_has_real_points = true;
+					if(!only_explicit_placeholders) {
+						const double sec = atof(pt);
+						if(sec > 0.0) {
+							uint32_t samples = (uint32_t)(sec * (double)sample_rate);
+							/* Restrict seekpoints to two per second of audio. */
+							samples = samples < sample_rate / 2 ? sample_rate / 2 : samples;
+							if(samples > 0) {
+								/* +1 for the initial point at sample 0 */
+								if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(seektable_template, samples, total_samples_to_encode))
+									return false;
+							}
+						}
+					}
+				}
+			}
+			else { /* -S # */
+				if(0 != spec_has_real_points)
+					*spec_has_real_points = true;
+				if(!only_explicit_placeholders) {
+					char *endptr;
+					const FLAC__int64 n = (FLAC__int64)strtoll(pt, &endptr, 10);
+					if(
+						(n > 0 || (endptr > pt && *endptr == ';')) && /* is a valid number (extra check needed for "0") */
+						(total_samples_to_encode == 0 || (FLAC__uint64)n < total_samples_to_encode) /* number is not >= the known total_samples_to_encode */
+					)
+						if(!FLAC__metadata_object_seektable_template_append_point(seektable_template, (FLAC__uint64)n))
+							return false;
+				}
+			}
+		}
+
+		pt = ++q;
+	}
+
+	if(!FLAC__metadata_object_seektable_template_sort(seektable_template, /*compact=*/true))
+		return false;
+
+	return true;
+}
diff --git a/src/share/grabbag/snprintf.c b/src/share/grabbag/snprintf.c
new file mode 100644
index 0000000..d8e4be3
--- /dev/null
+++ b/src/share/grabbag/snprintf.c
@@ -0,0 +1,101 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2013-2016  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 <stdio.h>
+#include <stdarg.h>
+
+#include "share/compat.h"
+
+/*
+ * 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.
+ *
+ * The important difference occurs when the resultant string (plus string
+ * terminator) would have been longer than the supplied size parameter. When
+ * this happens, ISO C's snprintf returns the length of resultant string, but
+ * does not over-write the end of the buffer. MS's snprintf_s in this case
+ * returns -1.
+ *
+ * The _MSC_VER code below attempts to modify the return code for vsnprintf_s
+ * to something that is more compatible with the behaviour of the ISO C version.
+ */
+
+int
+flac_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+	va_list va;
+	int rc;
+
+#if defined _MSC_VER
+	if (size == 0)
+		return 1024;
+#endif
+
+	va_start (va, fmt);
+
+#if defined _MSC_VER
+	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;
+}
+
+int
+flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va)
+{
+	int rc;
+
+#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
+
+	return rc;
+}
diff --git a/src/share/replaygain_analysis/CMakeLists.txt b/src/share/replaygain_analysis/CMakeLists.txt
new file mode 100644
index 0000000..4362b90
--- /dev/null
+++ b/src/share/replaygain_analysis/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(replaygain_analysis STATIC
+    replaygain_analysis.c)
diff --git a/src/share/replaygain_analysis/Makefile.lite b/src/share/replaygain_analysis/Makefile.lite
new file mode 100644
index 0000000..4fa2cc9
--- /dev/null
+++ b/src/share/replaygain_analysis/Makefile.lite
@@ -0,0 +1,15 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+LIB_NAME = libreplaygain_analysis
+INCLUDES = -I$(topdir)/include
+
+SRCS_C = \
+	replaygain_analysis.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/replaygain_analysis/replaygain_analysis.c b/src/share/replaygain_analysis/replaygain_analysis.c
new file mode 100644
index 0000000..37b77ab
--- /dev/null
+++ b/src/share/replaygain_analysis/replaygain_analysis.c
@@ -0,0 +1,575 @@
+/*
+ *  ReplayGainAnalysis - analyzes input samples and give the recommended dB change
+ *  Copyright (C) 2001 David Robinson and Glen Sawyer
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  concept and filter values by David Robinson (David@Robinson.org)
+ *    -- blame him if you think the idea is flawed
+ *  original coding by Glen Sawyer (glensawyer@hotmail.com)
+ *    -- blame him if you think this runs too slowly, or the coding is otherwise flawed
+ *
+ *  lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ )
+ *    -- credit him for all the _good_ programming ;)
+ *
+ *  minor cosmetic tweaks to integrate with FLAC by Josh Coalson
+ *
+ *
+ *  For an explanation of the concepts and the basic algorithms involved, go to:
+ *    http://www.replaygain.org/
+ */
+
+/*
+ *  Here's the deal. Call
+ *
+ *    InitGainAnalysis ( long samplefreq );
+ *
+ *  to initialize everything. Call
+ *
+ *    AnalyzeSamples ( const flac_float_t*  left_samples,
+ *                     const flac_float_t*  right_samples,
+ *                     size_t          num_samples,
+ *                     int             num_channels );
+ *
+ *  as many times as you want, with as many or as few samples as you want.
+ *  If mono, pass the sample buffer in through left_samples, leave
+ *  right_samples NULL, and make sure num_channels = 1.
+ *
+ *    GetTitleGain()
+ *
+ *  will return the recommended dB level change for all samples analyzed
+ *  SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis().
+ *
+ *    GetAlbumGain()
+ *
+ *  will return the recommended dB level change for all samples analyzed
+ *  since InitGainAnalysis() was called and finalized with GetTitleGain().
+ *
+ *  Pseudo-code to process an album:
+ *
+ *    flac_float_t       l_samples [4096];
+ *    flac_float_t       r_samples [4096];
+ *    size_t        num_samples;
+ *    uint32_t  num_songs;
+ *    uint32_t  i;
+ *
+ *    InitGainAnalysis ( 44100 );
+ *    for ( i = 1; i <= num_songs; i++ ) {
+ *        while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 )
+ *            AnalyzeSamples ( left_samples, right_samples, num_samples, 2 );
+ *        fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() );
+ *    }
+ *    fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() );
+ */
+
+/*
+ *  So here's the main source of potential code confusion:
+ *
+ *  The filters applied to the incoming samples are IIR filters,
+ *  meaning they rely on up to <filter order> number of previous samples
+ *  AND up to <filter order> number of previous filtered samples.
+ *
+ *  I set up the AnalyzeSamples routine to minimize memory usage and interface
+ *  complexity. The speed isn't compromised too much (I don't think), but the
+ *  internal complexity is higher than it should be for such a relatively
+ *  simple routine.
+ *
+ *  Optimization/clarity suggestions are welcome.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/replaygain_analysis.h"
+
+flac_float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */
+
+#define YULE_ORDER         10
+#define BUTTER_ORDER        2
+#define RMS_PERCENTILE      0.95        /* percentile which is louder than the proposed level */
+#define RMS_WINDOW_TIME    50           /* Time slice size [ms] */
+#define STEPS_per_dB      100.          /* Table entries per dB */
+#define MAX_dB            120.          /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */
+
+#define MAX_ORDER               (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER)
+#define PINK_REF                64.82 /* 298640883795 */                          /* calibration value */
+
+static flac_float_t          linprebuf [MAX_ORDER * 2];
+static flac_float_t*         linpre;                                          /* left input samples, with pre-buffer */
+static flac_float_t*         lstepbuf;
+static flac_float_t*         lstep;                                           /* left "first step" (i.e. post first filter) samples */
+static flac_float_t*         loutbuf;
+static flac_float_t*         lout;                                            /* left "out" (i.e. post second filter) samples */
+static flac_float_t          rinprebuf [MAX_ORDER * 2];
+static flac_float_t*         rinpre;                                          /* right input samples ... */
+static flac_float_t*         rstepbuf;
+static flac_float_t*         rstep;
+static flac_float_t*         routbuf;
+static flac_float_t*         rout;
+static uint32_t              sampleWindow;                           /* number of samples required to reach number of milliseconds required for RMS window */
+static uint64_t	        totsamp;
+static double           lsum;
+static double           rsum;
+#if 0
+static uint32_t  A [(size_t)(STEPS_per_dB * MAX_dB)];
+static uint32_t  B [(size_t)(STEPS_per_dB * MAX_dB)];
+#else
+/* [JEC] Solaris Forte compiler doesn't like float calc in array indices */
+static uint32_t  A [120 * 100];
+static uint32_t  B [120 * 100];
+#endif
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4305 )
+#endif
+
+struct ReplayGainFilter {
+    long rate;
+    uint32_t downsample;
+    flac_float_t BYule[YULE_ORDER+1];
+    flac_float_t AYule[YULE_ORDER+1];
+    flac_float_t BButter[BUTTER_ORDER+1];
+    flac_float_t AButter[BUTTER_ORDER+1];
+};
+
+static struct ReplayGainFilter *replaygainfilter;
+
+static const struct ReplayGainFilter ReplayGainFilters[] = {
+
+    {
+        48000, 0, /* ORIGINAL */
+        { 0.03857599435200,  -0.02160367184185,  -0.00123395316851,  -0.00009291677959,  -0.01655260341619,   0.02161526843274,  -0.02074045215285,   0.00594298065125,   0.00306428023191,   0.00012025322027,   0.00288463683916 },
+        { 1.00000000000000,  -3.84664617118067,   7.81501653005538, -11.34170355132042,  13.05504219327545, -12.28759895145294,   9.48293806319790, -5.87257861775999,   2.75465861874613,   -0.86984376593551,   0.13919314567432 },
+        { 0.98621192462708,  -1.97242384925416,   0.98621192462708 },
+        { 1.00000000000000,  -1.97223372919527,   0.97261396931306 },
+    },
+
+    {
+        44100, 0, /* ORIGINAL */
+        { 0.05418656406430,  -0.02911007808948,  -0.00848709379851,  -0.00851165645469,  -0.00834990904936,   0.02245293253339,  -0.02596338512915,   0.01624864962975,  -0.00240879051584,   0.00674613682247,  -0.00187763777362 },
+        { 1.00000000000000,  -3.47845948550071,   6.36317777566148,  -8.54751527471874,   9.47693607801280,  -8.81498681370155,   6.85401540936998,  -4.39470996079559,   2.19611684890774,  -0.75104302451432,   0.13149317958808 },
+        { 0.98500175787242,  -1.97000351574484,   0.98500175787242 },
+        { 1.00000000000000,  -1.96977855582618,   0.97022847566350 },
+    },
+
+    {
+        37800, 0,
+        { 0.10296717174470,  -0.04877975583256,  -0.02878009075237,  -0.03519509188311,   0.02888717172493,  -0.00609872684844,   0.00209851217112,   0.00911704668543,   0.01154404718589,  -0.00630293688700,   0.00107527155228 },
+        { 1.00000000000000,  -2.64848054923531,   3.58406058405771,  -3.83794914179161,   3.90142345804575,  -3.50179818637243,   2.67085284083076,  -1.82581142372418,   1.09530368139801,  -0.47689017820395,   0.11171431535905 },
+        { 0.98252400815195,  -1.96504801630391,   0.98252400815195 },
+        { 1.00000000000000,  -1.96474258269041,   0.96535344991740 },
+    },
+
+    {
+        36000, 0,
+        { 0.11572297028613,  -0.04120916051252,  -0.04977731768022,  -0.01047308680426,   0.00750863219157,   0.00055507694408,   0.00140344192886,   0.01286095246036,   0.00998223033885,  -0.00725013810661,   0.00326503346879 },
+        { 1.00000000000000,  -2.43606802820871,   3.01907406973844,  -2.90372016038192,   2.67947188094303,  -2.17606479220391,   1.44912956803015,  -0.87785765549050,   0.53592202672557,  -0.26469344817509,   0.07495878059717 },
+        { 0.98165826840326,  -1.96331653680652,   0.98165826840326 },
+        { 1.00000000000000,  -1.96298008938934,   0.96365298422371 },
+    },
+
+    {
+        32000, 0, /* ORIGINAL */
+        { 0.15457299681924,  -0.09331049056315,  -0.06247880153653,   0.02163541888798,  -0.05588393329856,   0.04781476674921,   0.00222312597743,   0.03174092540049,  -0.01390589421898,   0.00651420667831,  -0.00881362733839 },
+        { 1.00000000000000,  -2.37898834973084,   2.84868151156327,  -2.64577170229825,   2.23697657451713,  -1.67148153367602,   1.00595954808547,  -0.45953458054983,   0.16378164858596,  -0.05032077717131,   0.02347897407020 },
+        { 0.97938932735214,  -1.95877865470428,   0.97938932735214 },
+        { 1.00000000000000,  -1.95835380975398,   0.95920349965459 },
+    },
+
+    {
+        28000, 0,
+        { 0.23882392323383,  -0.22007791534089,  -0.06014581950332,   0.05004458058021,  -0.03293111254977,   0.02348678189717,   0.04290549799671,  -0.00938141862174,   0.00015095146303,  -0.00712601540885,  -0.00626520210162 },
+        { 1.00000000000000,  -2.06894080899139,   1.76944699577212,  -0.81404732584187,   0.25418286850232,  -0.30340791669762,   0.35616884070937,  -0.14967310591258,  -0.07024154183279,   0.11078404345174,  -0.03551838002425 },
+        { 0.97647981663949,  -1.95295963327897,   0.97647981663949 },
+        { 1.00000000000000,  -1.95240635772520,   0.95351290883275 },
+
+    },
+
+    {
+        24000, 0, /* ORIGINAL */
+        { 0.30296907319327,  -0.22613988682123,  -0.08587323730772,   0.03282930172664,  -0.00915702933434,  -0.02364141202522,  -0.00584456039913,   0.06276101321749,  -0.00000828086748,   0.00205861885564,  -0.02950134983287 },
+        { 1.00000000000000,  -1.61273165137247,   1.07977492259970,  -0.25656257754070,  -0.16276719120440,  -0.22638893773906,   0.39120800788284,  -0.22138138954925,   0.04500235387352,   0.02005851806501,   0.00302439095741 },
+        { 0.97531843204928,  -1.95063686409857,   0.97531843204928 },
+        { 1.00000000000000,  -1.95002759149878,   0.95124613669835 },
+    },
+
+    {
+        22050, 0, /* ORIGINAL */
+        { 0.33642304856132,  -0.25572241425570,  -0.11828570177555,   0.11921148675203,  -0.07834489609479,  -0.00469977914380,  -0.00589500224440,   0.05724228140351,   0.00832043980773,  -0.01635381384540,  -0.01760176568150 },
+        { 1.00000000000000,  -1.49858979367799,   0.87350271418188,   0.12205022308084,  -0.80774944671438,   0.47854794562326,  -0.12453458140019,  -0.04067510197014,   0.08333755284107,  -0.04237348025746,   0.02977207319925 },
+        { 0.97316523498161,  -1.94633046996323,   0.97316523498161 },
+        { 1.00000000000000,  -1.94561023566527,   0.94705070426118 },
+    },
+
+    {
+        18900, 0,
+        { 0.38412657295385,  -0.44533729608120,   0.20426638066221,  -0.28031676047946,   0.31484202614802,  -0.26078311203207,   0.12925201224848,  -0.01141164696062,   0.03036522115769,  -0.03776339305406,   0.00692036603586 },
+        { 1.00000000000000,  -1.74403915585708,   1.96686095832499,  -2.10081452941881,   1.90753918182846,  -1.83814263754422,   1.36971352214969,  -0.77883609116398,   0.39266422457649,  -0.12529383592986,   0.05424760697665 },
+        { 0.96535326815829,  -1.93070653631658,   0.96535326815829 },
+        { 1.00000000000000,  -1.92950577983524,   0.93190729279793 },
+    },
+
+    {
+        16000, 0, /* ORIGINAL */
+        { 0.44915256608450,  -0.14351757464547,  -0.22784394429749,  -0.01419140100551,   0.04078262797139,  -0.12398163381748,   0.04097565135648,   0.10478503600251,  -0.01863887810927,  -0.03193428438915,   0.00541907748707 },
+        { 1.00000000000000,  -0.62820619233671,   0.29661783706366,  -0.37256372942400,   0.00213767857124,  -0.42029820170918,   0.22199650564824,   0.00613424350682,   0.06747620744683,   0.05784820375801,   0.03222754072173 },
+        { 0.96454515552826,  -1.92909031105652,   0.96454515552826 },
+        { 1.00000000000000,  -1.92783286977036,   0.93034775234268 },
+    },
+
+    {
+        12000, 0, /* ORIGINAL */
+        { 0.56619470757641,  -0.75464456939302,   0.16242137742230,   0.16744243493672,  -0.18901604199609,   0.30931782841830,  -0.27562961986224,   0.00647310677246,   0.08647503780351,  -0.03788984554840,  -0.00588215443421 },
+        { 1.00000000000000,  -1.04800335126349,   0.29156311971249,  -0.26806001042947,   0.00819999645858,   0.45054734505008,  -0.33032403314006,   0.06739368333110,  -0.04784254229033,   0.01639907836189,   0.01807364323573 },
+        { 0.96009142950541,  -1.92018285901082,   0.96009142950541 },
+        { 1.00000000000000,  -1.91858953033784,   0.92177618768381 },
+    },
+
+    {
+        11025, 0, /* ORIGINAL */
+        { 0.58100494960553,  -0.53174909058578,  -0.14289799034253,   0.17520704835522,   0.02377945217615,   0.15558449135573,  -0.25344790059353,   0.01628462406333,   0.06920467763959,  -0.03721611395801,  -0.00749618797172 },
+        { 1.00000000000000,  -0.51035327095184,  -0.31863563325245,  -0.20256413484477,   0.14728154134330,   0.38952639978999,  -0.23313271880868,  -0.05246019024463,  -0.02505961724053,   0.02442357316099,   0.01818801111503 },
+        { 0.95856916599601,  -1.91713833199203,   0.95856916599601 },
+        { 1.00000000000000,  -1.91542108074780,   0.91885558323625 },
+    },
+
+    {
+        8000, 0, /* ORIGINAL */
+        { 0.53648789255105,  -0.42163034350696,  -0.00275953611929,   0.04267842219415,  -0.10214864179676,   0.14590772289388,  -0.02459864859345,  -0.11202315195388,  -0.04060034127000,   0.04788665548180,  -0.02217936801134 },
+        { 1.00000000000000,  -0.25049871956020,  -0.43193942311114,  -0.03424681017675,  -0.04678328784242,   0.26408300200955,   0.15113130533216,  -0.17556493366449,  -0.18823009262115,   0.05477720428674,   0.04704409688120 },
+        { 0.94597685600279,  -1.89195371200558,   0.94597685600279 },
+        { 1.00000000000000,  -1.88903307939452,   0.89487434461664 },
+    },
+
+};
+
+#ifdef _MSC_VER
+#pragma warning ( default : 4305 )
+#endif
+
+/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */
+
+static void
+filter ( const flac_float_t* input, flac_float_t* output, size_t nSamples, const flac_float_t* a, const flac_float_t* b, size_t order, uint32_t downsample )
+{
+    double  y;
+    size_t  i;
+    size_t  k;
+
+    const flac_float_t* input_head = input;
+    const flac_float_t* input_tail;
+
+    flac_float_t* output_head = output;
+    flac_float_t* output_tail;
+
+    for ( i = 0; i < nSamples; i++, input_head += downsample, ++output_head ) {
+
+        input_tail = input_head;
+        output_tail = output_head;
+
+        y = *input_head * b[0];
+
+        for ( k = 1; k <= order; k++ ) {
+            input_tail -= downsample;
+            --output_tail;
+            y += *input_tail * b[k] - *output_tail * a[k];
+        }
+
+        output[i] = (flac_float_t)y;
+    }
+}
+
+/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */
+
+static struct ReplayGainFilter*
+CreateGainFilter ( long samplefreq )
+{
+    uint32_t i;
+    long maxrate = 0;
+    uint32_t downsample = 1;
+    struct ReplayGainFilter* gainfilter = malloc(sizeof(*gainfilter));
+
+    if ( !gainfilter )
+        return 0;
+
+    while (1) {
+        for ( i = 0; i < sizeof(ReplayGainFilters)/sizeof(ReplayGainFilters[0]); ++i ) {
+            if (maxrate < ReplayGainFilters[i].rate)
+                maxrate = ReplayGainFilters[i].rate;
+
+            if ( ReplayGainFilters[i].rate == samplefreq ) {
+                *gainfilter = ReplayGainFilters[i];
+                gainfilter->downsample = downsample;
+                return gainfilter;
+            }
+        }
+
+        if (samplefreq < maxrate)
+            break;
+
+        while (samplefreq > maxrate) {
+            downsample *= 2;
+            samplefreq /= 2;
+        }
+    }
+
+    free(gainfilter);
+
+    return 0;
+}
+
+static void*
+ReallocateWindowBuffer(uint32_t window_size, flac_float_t **window_buffer)
+{
+    *window_buffer = safe_realloc_(*window_buffer, sizeof(**window_buffer) * (window_size + MAX_ORDER));
+    return *window_buffer;
+}
+
+static int
+ResetSampleFrequency ( long samplefreq ) {
+    int  i;
+
+    free(replaygainfilter);
+
+    replaygainfilter = CreateGainFilter( samplefreq );
+
+    if ( ! replaygainfilter)
+        return INIT_GAIN_ANALYSIS_ERROR;
+
+    sampleWindow =
+        (replaygainfilter->rate * RMS_WINDOW_TIME + 1000-1) / 1000;
+
+    if ( ! ReallocateWindowBuffer(sampleWindow, &lstepbuf) ||
+         ! ReallocateWindowBuffer(sampleWindow, &rstepbuf) ||
+         ! ReallocateWindowBuffer(sampleWindow, &loutbuf)  ||
+         ! ReallocateWindowBuffer(sampleWindow, &routbuf) ) {
+
+        return INIT_GAIN_ANALYSIS_ERROR;
+    }
+
+    /* zero out initial values */
+    for ( i = 0; i < MAX_ORDER; i++ )
+        linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.;
+
+    lsum         = 0.;
+    rsum         = 0.;
+    totsamp      = 0;
+
+    memset ( A, 0, sizeof(A) );
+
+    return INIT_GAIN_ANALYSIS_OK;
+}
+
+int
+ValidGainFrequency ( long samplefreq )
+{
+    struct ReplayGainFilter* gainfilter = CreateGainFilter( samplefreq );
+
+    if (gainfilter == 0) {
+        return 0;
+    } else {
+        free(gainfilter);
+        return 1;
+    }
+}
+
+int
+InitGainAnalysis ( long samplefreq )
+{
+    if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) {
+            return INIT_GAIN_ANALYSIS_ERROR;
+    }
+
+    linpre       = linprebuf + MAX_ORDER;
+    rinpre       = rinprebuf + MAX_ORDER;
+    lstep        = lstepbuf  + MAX_ORDER;
+    rstep        = rstepbuf  + MAX_ORDER;
+    lout         = loutbuf   + MAX_ORDER;
+    rout         = routbuf   + MAX_ORDER;
+
+    memset ( B, 0, sizeof(B) );
+
+    return INIT_GAIN_ANALYSIS_OK;
+}
+
+/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */
+
+int
+AnalyzeSamples ( const flac_float_t* left_samples, const flac_float_t* right_samples, size_t num_samples, int num_channels )
+{
+    uint32_t        downsample = replaygainfilter->downsample;
+    const flac_float_t*  curleft;
+    const flac_float_t*  curright;
+    long            prebufsamples;
+    long            batchsamples;
+    long            cursamples;
+    long            cursamplepos;
+    int             i;
+
+    num_samples /= downsample;
+
+    if ( num_samples == 0 )
+        return GAIN_ANALYSIS_OK;
+
+    cursamplepos = 0;
+    batchsamples = num_samples;
+
+    switch ( num_channels) {
+    case  1: right_samples = left_samples;
+    case  2: break;
+    default: return GAIN_ANALYSIS_ERROR;
+    }
+
+    prebufsamples = MAX_ORDER;
+    if ((size_t) prebufsamples > num_samples)
+        prebufsamples = num_samples;
+
+    for ( i = 0; i < prebufsamples; ++i ) {
+        linprebuf[i+MAX_ORDER] = left_samples [i * downsample];
+        rinprebuf[i+MAX_ORDER] = right_samples[i * downsample];
+    }
+
+    while ( batchsamples > 0 ) {
+        cursamples = batchsamples > (long)(sampleWindow-totsamp)  ?  (long)(sampleWindow - totsamp)  :  batchsamples;
+        if ( cursamplepos < MAX_ORDER ) {
+            downsample = 1;
+            curleft  = linpre+cursamplepos;
+            curright = rinpre+cursamplepos;
+            if (cursamples > MAX_ORDER - cursamplepos )
+                cursamples = MAX_ORDER - cursamplepos;
+        }
+        else {
+            downsample = replaygainfilter->downsample;
+            curleft  = left_samples  + cursamplepos * downsample;
+            curright = right_samples + cursamplepos * downsample;
+        }
+
+        filter ( curleft , lstep + totsamp, cursamples, replaygainfilter->AYule, replaygainfilter->BYule, YULE_ORDER, downsample );
+        filter ( curright, rstep + totsamp, cursamples, replaygainfilter->AYule, replaygainfilter->BYule, YULE_ORDER, downsample );
+
+        filter ( lstep + totsamp, lout + totsamp, cursamples, replaygainfilter->AButter, replaygainfilter->BButter, BUTTER_ORDER, 1 );
+        filter ( rstep + totsamp, rout + totsamp, cursamples, replaygainfilter->AButter, replaygainfilter->BButter, BUTTER_ORDER, 1 );
+
+        for ( i = 0; i < cursamples; i++ ) {             /* Get the squared values */
+            lsum += lout [totsamp+i] * lout [totsamp+i];
+            rsum += rout [totsamp+i] * rout [totsamp+i];
+        }
+
+        batchsamples -= cursamples;
+        cursamplepos += cursamples;
+        totsamp      += cursamples;
+        if ( totsamp == sampleWindow ) {  /* Get the Root Mean Square (RMS) for this set of samples */
+            double  val  = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 );
+            int     ival = (int) val;
+            if ( ival <                     0 ) ival = 0;
+            if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = (int)(sizeof(A)/sizeof(*A)) - 1;
+            A [ival]++;
+            lsum = rsum = 0.;
+            memmove ( loutbuf , loutbuf  + totsamp, MAX_ORDER * sizeof(flac_float_t) );
+            memmove ( routbuf , routbuf  + totsamp, MAX_ORDER * sizeof(flac_float_t) );
+            memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(flac_float_t) );
+            memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(flac_float_t) );
+            totsamp = 0;
+        }
+        if ( totsamp > sampleWindow )   /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */
+            return GAIN_ANALYSIS_ERROR;
+    }
+
+    if ( num_samples < MAX_ORDER ) {
+        memmove ( linprebuf,                           linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(flac_float_t) );
+        memmove ( rinprebuf,                           rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(flac_float_t) );
+        memcpy  ( linprebuf + MAX_ORDER - num_samples, left_samples,          num_samples             * sizeof(flac_float_t) );
+        memcpy  ( rinprebuf + MAX_ORDER - num_samples, right_samples,         num_samples             * sizeof(flac_float_t) );
+    }
+    else {
+        downsample = replaygainfilter->downsample;
+
+        left_samples  += (num_samples - MAX_ORDER) * downsample;
+        right_samples += (num_samples - MAX_ORDER) * downsample;
+
+        for ( i = 0; i < MAX_ORDER; ++i ) {
+            linprebuf[i] = left_samples [i * downsample];
+            rinprebuf[i] = right_samples[i * downsample];
+        }
+    }
+
+    return GAIN_ANALYSIS_OK;
+}
+
+
+static flac_float_t
+analyzeResult ( uint32_t* Array, size_t len )
+{
+    uint32_t  elems;
+    int32_t   upper;
+    size_t    i;
+
+    elems = 0;
+    for ( i = 0; i < len; i++ )
+        elems += Array[i];
+    if ( elems == 0 )
+        return GAIN_NOT_ENOUGH_SAMPLES;
+
+/* workaround for GCC bug #61423: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61423 */
+#if 0
+    upper = (int32_t) ceil (elems * (1. - RMS_PERCENTILE));
+#else
+    upper = (int32_t) (elems / 20 + ((elems % 20) ? 1 : 0));
+#endif
+    for ( i = len; i-- > 0; ) {
+        if ( (upper -= Array[i]) <= 0 )
+            break;
+    }
+
+    return (flac_float_t) ((flac_float_t)PINK_REF - (flac_float_t)i / (flac_float_t)STEPS_per_dB);
+}
+
+
+flac_float_t
+GetTitleGain ( void )
+{
+    flac_float_t  retval;
+    uint32_t      i;
+
+    retval = analyzeResult ( A, sizeof(A)/sizeof(*A) );
+
+    for ( i = 0; i < sizeof(A)/sizeof(*A); i++ ) {
+        B[i] += A[i];
+        A[i]  = 0;
+    }
+
+    for ( i = 0; i < MAX_ORDER; i++ )
+        linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f;
+
+    totsamp = 0;
+    lsum    = rsum = 0.;
+    return retval;
+}
+
+
+flac_float_t
+GetAlbumGain ( void )
+{
+    return analyzeResult ( B, sizeof(B)/sizeof(*B) );
+}
+
+/* end of replaygain_analysis.c */
diff --git a/src/share/replaygain_analysis/replaygain_analysis_static.vcproj b/src/share/replaygain_analysis/replaygain_analysis_static.vcproj
new file mode 100644
index 0000000..9645da5
--- /dev/null
+++ b/src/share/replaygain_analysis/replaygain_analysis_static.vcproj
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="replaygain_analysis_static"

+	ProjectGUID="{4cefbc89-c215-11db-8314-0800200c9a66}"

+	RootNamespace="replaygain_analysis_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\..\include\share\replaygain_analysis.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\replaygain_analysis.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/share/replaygain_analysis/replaygain_analysis_static.vcxproj b/src/share/replaygain_analysis/replaygain_analysis_static.vcxproj
new file mode 100644
index 0000000..6824f81
--- /dev/null
+++ b/src/share/replaygain_analysis/replaygain_analysis_static.vcxproj
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc89-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>replaygain_analysis_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\replaygain_analysis.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="replaygain_analysis.c" />

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/replaygain_analysis/replaygain_analysis_static.vcxproj.filters b/src/share/replaygain_analysis/replaygain_analysis_static.vcxproj.filters
new file mode 100644
index 0000000..f1207d3
--- /dev/null
+++ b/src/share/replaygain_analysis/replaygain_analysis_static.vcxproj.filters
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{9e16659d-14e5-4477-be88-76193fff5d31}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\replaygain_analysis.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="replaygain_analysis.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/replaygain_synthesis/CMakeLists.txt b/src/share/replaygain_synthesis/CMakeLists.txt
new file mode 100644
index 0000000..0736f4f
--- /dev/null
+++ b/src/share/replaygain_synthesis/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(replaygain_synthesis STATIC
+    replaygain_synthesis.c)
diff --git a/src/share/replaygain_synthesis/Makefile.lite b/src/share/replaygain_synthesis/Makefile.lite
new file mode 100644
index 0000000..a944234
--- /dev/null
+++ b/src/share/replaygain_synthesis/Makefile.lite
@@ -0,0 +1,15 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+LIB_NAME = libreplaygain_synthesis
+INCLUDES = -I./include -I$(topdir)/include
+
+SRCS_C = \
+	replaygain_synthesis.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/replaygain_synthesis/replaygain_synthesis.c b/src/share/replaygain_synthesis/replaygain_synthesis.c
new file mode 100644
index 0000000..9881794
--- /dev/null
+++ b/src/share/replaygain_synthesis/replaygain_synthesis.c
@@ -0,0 +1,429 @@
+/* replaygain_synthesis - Routines for applying ReplayGain to a signal
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+/*
+ * This is an aggregation of pieces of code from John Edwards' WaveGain
+ * program.  Mostly cosmetic changes were made; otherwise, the dithering
+ * code is almost untouched and the gain processing was converted from
+ * processing a whole file to processing chunks of samples.
+ *
+ * The original copyright notices for WaveGain's dither.c and wavegain.c
+ * appear below:
+ */
+/*
+ * (c) 2002 John Edwards
+ * mostly lifted from work by Frank Klemm
+ * random functions for dithering.
+ */
+/*
+ * Copyright (C) 2002 John Edwards
+ * Additional code by Magnus Holmgren and Gian-Carlo Pascutto
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h> /* for memset() */
+#include <math.h>
+#include "share/compat.h"
+#include "share/replaygain_synthesis.h"
+#include "FLAC/assert.h"
+
+#define FLAC__I64L(x) x##LL
+
+
+/*
+ * the following is based on parts of dither.c
+ */
+
+
+/*
+ *  This is a simple random number generator with good quality for audio purposes.
+ *  It consists of two polycounters with opposite rotation direction and different
+ *  periods. The periods are coprime, so the total period is the product of both.
+ *
+ *     -------------------------------------------------------------------------------------------------
+ * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0|
+ * |   -------------------------------------------------------------------------------------------------
+ * |                                                                          |  |  |  |     |        |
+ * |                                                                          +--+--+--+-XOR-+--------+
+ * |                                                                                      |
+ * +--------------------------------------------------------------------------------------+
+ *
+ *     -------------------------------------------------------------------------------------------------
+ *     |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+
+ *     -------------------------------------------------------------------------------------------------   |
+ *       |  |           |  |                                                                               |
+ *       +--+----XOR----+--+                                                                               |
+ *                |                                                                                        |
+ *                +----------------------------------------------------------------------------------------+
+ *
+ *
+ *  The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481,
+ *  which gives a period of 18.410.713.077.675.721.215. The result is the
+ *  XORed values of both generators.
+ */
+
+static uint32_t random_int_(void)
+{
+	static const uint8_t parity_[256] = {
+		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
+	};
+	static uint32_t r1_ = 1;
+	static uint32_t r2_ = 1;
+
+	uint32_t t1, t2, t3, t4;
+
+	/* Parity calculation is done via table lookup, this is also available
+	 * on CPUs without parity, can be implemented in C and avoid unpredictable
+	 * jumps and slow rotate through the carry flag operations.
+	 */
+	t3   = t1 = r1_;    t4   = t2 = r2_;
+	t1  &= 0xF5;        t2 >>= 25;
+	t1   = parity_[t1]; t2  &= 0x63;
+	t1 <<= 31;          t2   = parity_[t2];
+
+	return (r1_ = (t3 >> 1) | t1 ) ^ (r2_ = (t4 + t4) | t2 );
+}
+
+/* gives a equal distributed random number */
+/* between -2^31*mult and +2^31*mult */
+static double random_equi_(double mult)
+{
+	return mult * (int) random_int_();
+}
+
+/* gives a triangular distributed random number */
+/* between -2^32*mult and +2^32*mult */
+static double random_triangular_(double mult)
+{
+	return mult * ( (double) (int) random_int_() + (double) (int) random_int_() );
+}
+
+
+static const float  F44_0 [16 + 32] = {
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0
+};
+
+
+static const float  F44_1 [16 + 32] = {  /* SNR(w) = 4.843163 dB, SNR = -3.192134 dB */
+	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+
+	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+
+	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+};
+
+
+static const float  F44_2 [16 + 32] = {  /* SNR(w) = 10.060213 dB, SNR = -12.766730 dB */
+	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+
+	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+
+	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+};
+
+
+static const float  F44_3 [16 + 32] = {  /* SNR(w) = 15.382598 dB, SNR = -29.402334 dB */
+	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
+
+	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
+
+	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099
+};
+
+
+static double scalar16_(const float* x, const float* y)
+{
+	return
+		x[ 0]*y[ 0] + x[ 1]*y[ 1] + x[ 2]*y[ 2] + x[ 3]*y[ 3] +
+		x[ 4]*y[ 4] + x[ 5]*y[ 5] + x[ 6]*y[ 6] + x[ 7]*y[ 7] +
+		x[ 8]*y[ 8] + x[ 9]*y[ 9] + x[10]*y[10] + x[11]*y[11] +
+		x[12]*y[12] + x[13]*y[13] + x[14]*y[14] + x[15]*y[15];
+}
+
+
+void FLAC__replaygain_synthesis__init_dither_context(DitherContext *d, int bits, int shapingtype)
+{
+	static uint8_t default_dither [] = { 92, 92, 88, 84, 81, 78, 74, 67,  0,  0 };
+	static const float*               F [] = { F44_0, F44_1, F44_2, F44_3 };
+
+	int indx;
+
+	if (shapingtype < 0) shapingtype = 0;
+	if (shapingtype > 3) shapingtype = 3;
+	d->ShapingType = (NoiseShaping)shapingtype;
+	indx = bits - 11 - shapingtype;
+	if (indx < 0) indx = 0;
+	if (indx > 9) indx = 9;
+
+	memset ( d->ErrorHistory , 0, sizeof (d->ErrorHistory ) );
+	memset ( d->DitherHistory, 0, sizeof (d->DitherHistory) );
+
+	d->FilterCoeff = F [shapingtype];
+	d->Mask   = ((FLAC__uint64)-1) << (32 - bits);
+	d->Add    = 0.5     * ((1L << (32 - bits)) - 1);
+	d->Dither = 0.01f*default_dither[indx] / (((FLAC__int64)1) << bits);
+	d->LastHistoryIndex = 0;
+}
+
+static inline int64_t
+ROUND64 (DitherContext *d, double x)
+{
+	union {
+		double d;
+		int64_t i;
+	} doubletmp;
+
+    doubletmp.d = x + d->Add + (int64_t)FLAC__I64L(0x001FFFFD80000000);
+
+    return doubletmp.i - (int64_t)FLAC__I64L(0x433FFFFD80000000);
+}
+
+/*
+ * the following is based on parts of wavegain.c
+ */
+
+static int64_t dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k)
+{
+	double Sum2;
+	int64_t val;
+
+	if(do_dithering) {
+		if(shapingtype == 0) {
+			double  tmp = random_equi_(d->Dither);
+			Sum2 = tmp - d->LastRandomNumber [k];
+			d->LastRandomNumber [k] = (int)tmp;
+			Sum2 = Sum += Sum2;
+			val = ROUND64(d, Sum2) & d->Mask;
+		}
+		else {
+			Sum2 = random_triangular_(d->Dither) - scalar16_(d->DitherHistory[k], d->FilterCoeff + i);
+			Sum += d->DitherHistory [k] [(-1-i)&15] = (float)Sum2;
+			Sum2 = Sum + scalar16_(d->ErrorHistory [k], d->FilterCoeff + i);
+			val = ROUND64(d, Sum2) & d->Mask;
+			d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val);
+		}
+		return val;
+	}
+
+	return ROUND64(d, Sum);
+}
+
+#if 0
+	float        peak = 0.f,
+	             new_peak,
+	             factor_clip
+	double       scale,
+	             dB;
+
+	...
+
+	peak is in the range -32768.0 .. 32767.0
+
+	/* calculate factors for ReplayGain and ClippingPrevention */
+	*track_gain = GetTitleGain() + settings->man_gain;
+	scale = (float) pow(10., *track_gain * 0.05);
+	if(settings->clip_prev) {
+		factor_clip  = (float) (32767./( peak + 1));
+		if(scale < factor_clip)
+			factor_clip = 1.f;
+		else
+			factor_clip /= scale;
+		scale *= factor_clip;
+	}
+	new_peak = (float) peak * scale;
+
+	dB = 20. * log10(scale);
+	*track_gain = (float) dB;
+
+ 	const double scale = pow(10., (double)gain * 0.05);
+#endif
+
+
+size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool uint32_t_data_out, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, const uint32_t source_bps, const uint32_t target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context)
+{
+	static const FLAC__int64 hard_clip_factors_[33] = {
+		0, /* 0 bits-per-sample (not supported) */
+		0, /* 1 bits-per-sample (not supported) */
+		0, /* 2 bits-per-sample (not supported) */
+		0, /* 3 bits-per-sample (not supported) */
+		-8, /* 4 bits-per-sample */
+		-16, /* 5 bits-per-sample */
+		-32, /* 6 bits-per-sample */
+		-64, /* 7 bits-per-sample */
+		-128, /* 8 bits-per-sample */
+		-256, /* 9 bits-per-sample */
+		-512, /* 10 bits-per-sample */
+		-1024, /* 11 bits-per-sample */
+		-2048, /* 12 bits-per-sample */
+		-4096, /* 13 bits-per-sample */
+		-8192, /* 14 bits-per-sample */
+		-16384, /* 15 bits-per-sample */
+		-32768, /* 16 bits-per-sample */
+		-65536, /* 17 bits-per-sample */
+		-131072, /* 18 bits-per-sample */
+		-262144, /* 19 bits-per-sample */
+		-524288, /* 20 bits-per-sample */
+		-1048576, /* 21 bits-per-sample */
+		-2097152, /* 22 bits-per-sample */
+		-4194304, /* 23 bits-per-sample */
+		-8388608, /* 24 bits-per-sample */
+		-16777216, /* 25 bits-per-sample */
+		-33554432, /* 26 bits-per-sample */
+		-67108864, /* 27 bits-per-sample */
+		-134217728, /* 28 bits-per-sample */
+		-268435456, /* 29 bits-per-sample */
+		-536870912, /* 30 bits-per-sample */
+		-1073741824, /* 31 bits-per-sample */
+		(FLAC__int64)(-1073741824) * 2 /* 32 bits-per-sample */
+	};
+	const FLAC__int32 conv_shift = 32 - target_bps;
+	const FLAC__int64 hard_clip_factor = hard_clip_factors_[target_bps];
+	/*
+	 * The integer input coming in has a varying range based on the
+	 * source_bps.  We want to normalize it to [-1.0, 1.0) so instead
+	 * of doing two multiplies on each sample, we just multiple
+	 * 'scale' by 1/(2^(source_bps-1))
+	 */
+	const double multi_scale = scale / (double)(1u << (source_bps-1));
+
+	FLAC__byte * const start = data_out;
+	uint32_t i, channel;
+	const FLAC__int32 *input_;
+	double sample;
+	const uint32_t bytes_per_sample = target_bps / 8;
+	const uint32_t last_history_index = dither_context->LastHistoryIndex;
+	NoiseShaping noise_shaping = dither_context->ShapingType;
+	FLAC__int64 val64;
+	FLAC__int32 val32;
+	FLAC__int32 uval32;
+	const FLAC__uint32 twiggle = 1u << (target_bps - 1);
+
+	FLAC__ASSERT(channels > 0 && channels <= FLAC_SHARE__MAX_SUPPORTED_CHANNELS);
+	FLAC__ASSERT(source_bps >= 4);
+	FLAC__ASSERT(target_bps >= 4);
+	FLAC__ASSERT(source_bps <= 32);
+	FLAC__ASSERT(target_bps < 32);
+	FLAC__ASSERT((target_bps & 7) == 0);
+
+	for(channel = 0; channel < channels; channel++) {
+		const uint32_t incr = bytes_per_sample * channels;
+		data_out = start + bytes_per_sample * channel;
+		input_ = input[channel];
+		for(i = 0; i < wide_samples; i++, data_out += incr) {
+			sample = (double)input_[i] * multi_scale;
+
+			if(hard_limit) {
+				/* hard 6dB limiting */
+				if(sample < -0.5)
+					sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5;
+				else if(sample > 0.5)
+					sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5;
+			}
+			sample *= 2147483647.;
+
+			val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) >> conv_shift;
+
+			val32 = (FLAC__int32)val64;
+			if(val64 >= -hard_clip_factor)
+				val32 = (FLAC__int32)(-(hard_clip_factor+1));
+			else if(val64 < hard_clip_factor)
+				val32 = (FLAC__int32)hard_clip_factor;
+
+			uval32 = (FLAC__uint32)val32;
+			if (uint32_t_data_out)
+				uval32 ^= twiggle;
+
+			if (little_endian_data_out) {
+				switch(target_bps) {
+					case 24:
+						data_out[2] = (FLAC__byte)(uval32 >> 16);
+						/* fall through */
+					case 16:
+						data_out[1] = (FLAC__byte)(uval32 >> 8);
+						/* fall through */
+					case 8:
+						data_out[0] = (FLAC__byte)uval32;
+						break;
+				}
+			}
+			else {
+				switch(target_bps) {
+					case 24:
+						data_out[0] = (FLAC__byte)(uval32 >> 16);
+						data_out[1] = (FLAC__byte)(uval32 >> 8);
+						data_out[2] = (FLAC__byte)uval32;
+						break;
+					case 16:
+						data_out[0] = (FLAC__byte)(uval32 >> 8);
+						data_out[1] = (FLAC__byte)uval32;
+						break;
+					case 8:
+						data_out[0] = (FLAC__byte)uval32;
+						break;
+				}
+			}
+		}
+	}
+	dither_context->LastHistoryIndex = (last_history_index + wide_samples) % 32;
+
+	return wide_samples * channels * (target_bps/8);
+}
diff --git a/src/share/replaygain_synthesis/replaygain_synthesis_static.vcproj b/src/share/replaygain_synthesis/replaygain_synthesis_static.vcproj
new file mode 100644
index 0000000..7e14883
--- /dev/null
+++ b/src/share/replaygain_synthesis/replaygain_synthesis_static.vcproj
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="replaygain_synthesis_static"

+	ProjectGUID="{4cefbc8a-c215-11db-8314-0800200c9a66}"

+	RootNamespace="replaygain_synthesis_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\..\include\share\replaygain_synthesis.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\replaygain_synthesis.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/share/replaygain_synthesis/replaygain_synthesis_static.vcxproj b/src/share/replaygain_synthesis/replaygain_synthesis_static.vcxproj
new file mode 100644
index 0000000..b8379c0
--- /dev/null
+++ b/src/share/replaygain_synthesis/replaygain_synthesis_static.vcxproj
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc8a-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>replaygain_synthesis_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\replaygain_synthesis.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="replaygain_synthesis.c" />

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/replaygain_synthesis/replaygain_synthesis_static.vcxproj.filters b/src/share/replaygain_synthesis/replaygain_synthesis_static.vcxproj.filters
new file mode 100644
index 0000000..ace3776
--- /dev/null
+++ b/src/share/replaygain_synthesis/replaygain_synthesis_static.vcxproj.filters
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{47ae72f8-630b-4044-b8ce-f4d560d70f4f}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\replaygain_synthesis.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="replaygain_synthesis.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/utf8/CMakeLists.txt b/src/share/utf8/CMakeLists.txt
new file mode 100644
index 0000000..389b09e
--- /dev/null
+++ b/src/share/utf8/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.12)
+
+add_library(utf8 STATIC
+    charset.c
+    iconvert.c
+    utf8.c)
+
+target_link_libraries(utf8 PUBLIC grabbag $<TARGET_NAME_IF_EXISTS:Iconv::Iconv>)
diff --git a/src/share/utf8/Makefile.lite b/src/share/utf8/Makefile.lite
new file mode 100644
index 0000000..ad50492
--- /dev/null
+++ b/src/share/utf8/Makefile.lite
@@ -0,0 +1,25 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+LIB_NAME = libutf8
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(ICONV_LIBS)
+else
+    LIBS = -lgrabbag $(ICONV_LIBS)
+endif
+
+INCLUDES = -I$(topdir)/include
+
+SRCS_C = \
+	charset.c \
+	iconvert.c \
+	utf8.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/utf8/charmaps.h b/src/share/utf8/charmaps.h
new file mode 100644
index 0000000..16d049a
--- /dev/null
+++ b/src/share/utf8/charmaps.h
@@ -0,0 +1,57 @@
+
+/*
+ * If you need to generate more maps, use makemap.c on a system
+ * with a decent iconv.
+ */
+
+static const uint16_t mapping_iso_8859_2[256] = {
+  0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+  0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+  0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+  0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+  0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+  0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+  0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+  0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+  0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+  0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+  0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+  0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+  0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+  0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+  0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+  0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+  0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+  0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+  0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+  0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+  0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7,
+  0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b,
+  0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7,
+  0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c,
+  0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
+  0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
+  0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
+  0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
+  0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
+  0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
+  0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
+  0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9
+};
+
+static struct {
+  const char *name;
+  const uint16_t *map;
+  struct charset *charset;
+} maps[] = {
+  { "ISO-8859-2", mapping_iso_8859_2, 0 },
+  { 0, 0, 0 }
+};
+
+static const struct {
+  const char *bad;
+  const char *good;
+} names[] = {
+  { "ANSI_X3.4-1968", "us-ascii" },
+  { 0, 0 }
+};
diff --git a/src/share/utf8/charset.c b/src/share/utf8/charset.c
new file mode 100644
index 0000000..5c5693d
--- /dev/null
+++ b/src/share/utf8/charset.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * See the corresponding header file for a description of the functions
+ * that this file provides.
+ *
+ * This was first written for Ogg Vorbis but could be of general use.
+ *
+ * The only deliberate assumption about data sizes is that a short has
+ * at least 16 bits, but this code has only been tested on systems with
+ * 8-bit char, 16-bit short and 32-bit int.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if !defined _WIN32 && !defined HAVE_ICONV /* should be && defined USE_CHARSET_CONVERT */
+
+#include <stdlib.h>
+
+#include "share/alloc.h"
+#include "charset.h"
+
+#include "charmaps.h"
+
+/*
+ * This is like the standard strcasecmp, but it does not depend
+ * on the locale. Locale-dependent functions can be dangerous:
+ * we once had a bug involving strcasecmp("iso", "ISO") in a
+ * Turkish locale!
+ *
+ * (I'm not really sure what the official standard says
+ * about the sign of strcasecmp("Z", "["), but usually
+ * we're only interested in whether it's zero.)
+ */
+
+static int ascii_strcasecmp(const char *s1, const char *s2)
+{
+  char c1, c2;
+
+  for (;; s1++, s2++) {
+    if (!*s1 || !*s2)
+      break;
+    if (*s1 == *s2)
+      continue;
+    c1 = *s1;
+    if ('a' <= c1 && c1 <= 'z')
+      c1 += 'A' - 'a';
+    c2 = *s2;
+    if ('a' <= c2 && c2 <= 'z')
+      c2 += 'A' - 'a';
+    if (c1 != c2)
+      break;
+  }
+  return (uint8_t)*s1 - (uint8_t)*s2;
+}
+
+/*
+ * UTF-8 equivalents of the C library's wctomb() and mbtowc().
+ */
+
+int utf8_mbtowc(int *pwc, const char *s, size_t n)
+{
+  uint8_t c;
+  int wc, i, k;
+
+  if (!n || !s)
+    return 0;
+
+  c = *s;
+  if (c < 0x80) {
+    if (pwc)
+      *pwc = c;
+    return c ? 1 : 0;
+  }
+  else if (c < 0xc2)
+    return -1;
+  else if (c < 0xe0) {
+    if (n >= 2 && (s[1] & 0xc0) == 0x80) {
+      if (pwc)
+	*pwc = ((c & 0x1f) << 6) | (s[1] & 0x3f);
+      return 2;
+    }
+    else
+      return -1;
+  }
+  else if (c < 0xf0)
+    k = 3;
+  else if (c < 0xf8)
+    k = 4;
+  else if (c < 0xfc)
+    k = 5;
+  else if (c < 0xfe)
+    k = 6;
+  else
+    return -1;
+
+  if (n < (size_t)k)
+    return -1;
+  wc = *s++ & ((1 << (7 - k)) - 1);
+  for (i = 1; i < k; i++) {
+    if ((*s & 0xc0) != 0x80)
+      return -1;
+    wc = (wc << 6) | (*s++ & 0x3f);
+  }
+  if (wc < (1 << (5 * k - 4)))
+    return -1;
+  if (pwc)
+    *pwc = wc;
+  return k;
+}
+
+int utf8_wctomb(char *s, int wc1)
+{
+  uint32_t wc = wc1;
+
+  if (!s)
+    return 0;
+  if (wc < (1u << 7)) {
+    *s++ = wc;
+    return 1;
+  }
+  else if (wc < (1u << 11)) {
+    *s++ = 0xc0 | (wc >> 6);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 2;
+  }
+  else if (wc < (1u << 16)) {
+    *s++ = 0xe0 | (wc >> 12);
+    *s++ = 0x80 | ((wc >> 6) & 0x3f);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 3;
+  }
+  else if (wc < (1u << 21)) {
+    *s++ = 0xf0 | (wc >> 18);
+    *s++ = 0x80 | ((wc >> 12) & 0x3f);
+    *s++ = 0x80 | ((wc >> 6) & 0x3f);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 4;
+  }
+  else if (wc < (1u << 26)) {
+    *s++ = 0xf8 | (wc >> 24);
+    *s++ = 0x80 | ((wc >> 18) & 0x3f);
+    *s++ = 0x80 | ((wc >> 12) & 0x3f);
+    *s++ = 0x80 | ((wc >> 6) & 0x3f);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 5;
+  }
+  else if (wc < (1u << 31)) {
+    *s++ = 0xfc | (wc >> 30);
+    *s++ = 0x80 | ((wc >> 24) & 0x3f);
+    *s++ = 0x80 | ((wc >> 18) & 0x3f);
+    *s++ = 0x80 | ((wc >> 12) & 0x3f);
+    *s++ = 0x80 | ((wc >> 6) & 0x3f);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 6;
+  }
+  else
+    return -1;
+}
+
+/*
+ * The charset "object" and methods.
+ */
+
+struct charset {
+  int max;
+  int (*mbtowc)(void *table, int *pwc, const char *s, size_t n);
+  int (*wctomb)(void *table, char *s, int wc);
+  void *map;
+};
+
+int charset_mbtowc(struct charset *charset, int *pwc, const char *s, size_t n)
+{
+  return (*charset->mbtowc)(charset->map, pwc, s, n);
+}
+
+int charset_wctomb(struct charset *charset, char *s, int wc)
+{
+  return (*charset->wctomb)(charset->map, s, wc);
+}
+
+int charset_max(struct charset *charset)
+{
+  return charset->max;
+}
+
+/*
+ * Implementation of UTF-8.
+ */
+
+static int mbtowc_utf8(void *map, int *pwc, const char *s, size_t n)
+{
+  (void)map;
+  return utf8_mbtowc(pwc, s, n);
+}
+
+static int wctomb_utf8(void *map, char *s, int wc)
+{
+  (void)map;
+  return utf8_wctomb(s, wc);
+}
+
+/*
+ * Implementation of US-ASCII.
+ * Probably on most architectures this compiles to less than 256 bytes
+ * of code, so we can save space by not having a table for this one.
+ */
+
+static int mbtowc_ascii(void *map, int *pwc, const char *s, size_t n)
+{
+  int wc;
+
+  (void)map;
+  if (!n || !s)
+    return 0;
+  wc = (uint8_t)*s;
+  if (wc & ~0x7f)
+    return -1;
+  if (pwc)
+    *pwc = wc;
+  return wc ? 1 : 0;
+}
+
+static int wctomb_ascii(void *map, char *s, int wc)
+{
+  (void)map;
+  if (!s)
+    return 0;
+  if (wc & ~0x7f)
+    return -1;
+  *s = wc;
+  return 1;
+}
+
+/*
+ * Implementation of ISO-8859-1.
+ * Probably on most architectures this compiles to less than 256 bytes
+ * of code, so we can save space by not having a table for this one.
+ */
+
+static int mbtowc_iso1(void *map, int *pwc, const char *s, size_t n)
+{
+  int wc;
+
+  (void)map;
+  if (!n || !s)
+    return 0;
+  wc = (uint8_t)*s;
+  if (wc & ~0xff)
+    return -1;
+  if (pwc)
+    *pwc = wc;
+  return wc ? 1 : 0;
+}
+
+static int wctomb_iso1(void *map, char *s, int wc)
+{
+  (void)map;
+  if (!s)
+    return 0;
+  if (wc & ~0xff)
+    return -1;
+  *s = wc;
+  return 1;
+}
+
+/*
+ * Implementation of any 8-bit charset.
+ */
+
+struct map {
+  const uint16_t *from;
+  struct inverse_map *to;
+};
+
+static int mbtowc_8bit(void *map1, int *pwc, const char *s, size_t n)
+{
+  struct map *map = map1;
+  uint16_t wc;
+
+  if (!n || !s)
+    return 0;
+  wc = map->from[(uint8_t)*s];
+  if (wc == 0xffff)
+    return -1;
+  if (pwc)
+    *pwc = (int)wc;
+  return wc ? 1 : 0;
+}
+
+/*
+ * For the inverse map we use a hash table, which has the advantages
+ * of small constant memory requirement and simple memory allocation,
+ * but the disadvantage of slow conversion in the worst case.
+ * If you need real-time performance while letting a potentially
+ * malicious user define their own map, then the method used in
+ * linux/drivers/char/consolemap.c would be more appropriate.
+ */
+
+struct inverse_map {
+  uint8_t first[256];
+  uint8_t next[256];
+};
+
+/*
+ * The simple hash is good enough for this application.
+ * Use the alternative trivial hashes for testing.
+ */
+#define HASH(i) ((i) & 0xff)
+/* #define HASH(i) 0 */
+/* #define HASH(i) 99 */
+
+static struct inverse_map *make_inverse_map(const uint16_t *from)
+{
+  struct inverse_map *to;
+  char used[256];
+  int i, j, k;
+
+  to = malloc(sizeof(struct inverse_map));
+  if (!to)
+    return 0;
+  for (i = 0; i < 256; i++)
+    to->first[i] = to->next[i] = used[i] = 0;
+  for (i = 255; i >= 0; i--)
+    if (from[i] != 0xffff) {
+      k = HASH(from[i]);
+      to->next[i] = to->first[k];
+      to->first[k] = i;
+      used[k] = 1;
+    }
+
+  /* Point the empty buckets at an empty list. */
+  for (i = 0; i < 256; i++)
+    if (!to->next[i])
+      break;
+  if (i < 256)
+    for (j = 0; j < 256; j++)
+      if (!used[j])
+	to->first[j] = i;
+
+  return to;
+}
+
+static int wctomb_8bit(void *map1, char *s, int wc1)
+{
+  struct map *map = map1;
+  uint16_t wc = wc1;
+  int i;
+
+  if (!s)
+    return 0;
+
+  if (wc1 & ~0xffff)
+    return -1;
+
+  if (1) /* Change 1 to 0 to test the case where malloc fails. */
+    if (!map->to)
+      map->to = make_inverse_map(map->from);
+
+  if (map->to) {
+    /* Use the inverse map. */
+    i = map->to->first[HASH(wc)];
+    for (;;) {
+      if (map->from[i] == wc) {
+	*s = i;
+	return 1;
+      }
+      if (!(i = map->to->next[i]))
+	break;
+    }
+  }
+  else {
+    /* We don't have an inverse map, so do a linear search. */
+    for (i = 0; i < 256; i++)
+      if (map->from[i] == wc) {
+	*s = i;
+	return 1;
+      }
+  }
+
+  return -1;
+}
+
+/*
+ * The "constructor" charset_find().
+ */
+
+struct charset charset_utf8 = {
+  6,
+  &mbtowc_utf8,
+  &wctomb_utf8,
+  0
+};
+
+struct charset charset_iso1 = {
+  1,
+  &mbtowc_iso1,
+  &wctomb_iso1,
+  0
+};
+
+struct charset charset_ascii = {
+  1,
+  &mbtowc_ascii,
+  &wctomb_ascii,
+  0
+};
+
+struct charset *charset_find(const char *code)
+{
+  int i;
+
+  /* Find good (MIME) name. */
+  for (i = 0; names[i].bad; i++)
+    if (!ascii_strcasecmp(code, names[i].bad)) {
+      code = names[i].good;
+      break;
+    }
+
+  /* Recognise some charsets for which we avoid using a table. */
+  if (!ascii_strcasecmp(code, "UTF-8"))
+    return &charset_utf8;
+  if (!ascii_strcasecmp(code, "US-ASCII"))
+    return &charset_ascii;
+  if (!ascii_strcasecmp(code, "ISO-8859-1"))
+    return &charset_iso1;
+
+  /* Look for a mapping for a simple 8-bit encoding. */
+  for (i = 0; maps[i].name; i++)
+    if (!ascii_strcasecmp(code, maps[i].name)) {
+      if (!maps[i].charset) {
+	maps[i].charset = malloc(sizeof(struct charset));
+	if (maps[i].charset) {
+	  struct map *map = malloc(sizeof(struct map));
+	  if (!map) {
+	    free(maps[i].charset);
+	    maps[i].charset = 0;
+	  }
+	  else {
+	    maps[i].charset->max = 1;
+	    maps[i].charset->mbtowc = &mbtowc_8bit;
+	    maps[i].charset->wctomb = &wctomb_8bit;
+	    maps[i].charset->map = map;
+	    map->from = maps[i].map;
+	    map->to = 0; /* inverse mapping is created when required */
+	  }
+	}
+      }
+      return maps[i].charset;
+    }
+
+  return 0;
+}
+
+/*
+ * Function to convert a buffer from one encoding to another.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ * Each of TO and TOLEN may be zero, if the result is not needed.
+ * The output buffer is null-terminated, so it is all right to
+ * use charset_convert(fromcode, tocode, s, strlen(s), &t, 0).
+ */
+
+int charset_convert(const char *fromcode, const char *tocode,
+		    const char *from, size_t fromlen,
+		    char **to, size_t *tolen)
+{
+  int ret = 0;
+  struct charset *charset1, *charset2;
+  char *tobuf, *p;
+  int i, j, wc;
+
+  charset1 = charset_find(fromcode);
+  charset2 = charset_find(tocode);
+  if (!charset1 || !charset2 )
+    return -1;
+
+  tobuf = safe_malloc_mul2add_(fromlen, /*times*/charset2->max, /*+*/1);
+  if (!tobuf)
+    return -2;
+
+  for (p = tobuf; fromlen; from += i, fromlen -= i, p += j) {
+    i = charset_mbtowc(charset1, &wc, from, fromlen);
+    if (!i)
+      i = 1;
+    else if (i == -1) {
+      i  = 1;
+      wc = '#';
+      ret = 2;
+    }
+    j = charset_wctomb(charset2, p, wc);
+    if (j == -1) {
+      if (!ret)
+	ret = 1;
+      j = charset_wctomb(charset2, p, '?');
+      if (j == -1)
+	j = 0;
+    }
+  }
+
+  if (tolen)
+    *tolen = p - tobuf;
+  *p++ = '\0';
+  if (to) {
+    char *tobuf_saved = tobuf;
+    *to = realloc(tobuf, p - tobuf);
+    if (*to == NULL)
+      *to = tobuf_saved;
+  }
+  else
+    free(tobuf);
+
+  return ret;
+}
+
+#endif /* USE_CHARSET_ICONV */
diff --git a/src/share/utf8/charset.h b/src/share/utf8/charset.h
new file mode 100644
index 0000000..ea8e31e
--- /dev/null
+++ b/src/share/utf8/charset.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+
+/*
+ * These functions are like the C library's mbtowc() and wctomb(),
+ * but instead of depending on the locale they always work in UTF-8,
+ * and they use int instead of wchar_t.
+ */
+
+int utf8_mbtowc(int *pwc, const char *s, size_t n);
+int utf8_wctomb(char *s, int wc);
+
+/*
+ * This is an object-oriented version of mbtowc() and wctomb().
+ * The caller first uses charset_find() to get a pointer to struct
+ * charset, then uses the mbtowc() and wctomb() methods on it.
+ * The function charset_max() gives the maximum length of a
+ * multibyte character in that encoding.
+ * This API is only appropriate for stateless encodings like UTF-8
+ * or ISO-8859-3, but I have no intention of implementing anything
+ * other than UTF-8 and 8-bit encodings.
+ *
+ * MINOR BUG: If there is no memory charset_find() may return 0 and
+ * there is no way to distinguish this case from an unknown encoding.
+ */
+
+struct charset;
+
+struct charset *charset_find(const char *code);
+
+int charset_mbtowc(struct charset *charset, int *pwc, const char *s, size_t n);
+int charset_wctomb(struct charset *charset, char *s, int wc);
+int charset_max(struct charset *charset);
+
+/*
+ * Function to convert a buffer from one encoding to another.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ * Each of TO and TOLEN may be zero if the result is not wanted.
+ * The input or output may contain null bytes, but the output
+ * buffer is also null-terminated, so it is all right to
+ * use charset_convert(fromcode, tocode, s, strlen(s), &t, 0).
+ *
+ * Return value:
+ *
+ *  -2 : memory allocation failed
+ *  -1 : unknown encoding
+ *   0 : data was converted exactly
+ *   1 : valid data was converted approximately (using '?')
+ *   2 : input was invalid (but still converted, using '#')
+ */
+
+int charset_convert(const char *fromcode, const char *tocode,
+		    const char *from, size_t fromlen,
+		    char **to, size_t *tolen);
diff --git a/src/share/utf8/charset_test.c b/src/share/utf8/charset_test.c
new file mode 100644
index 0000000..6761100
--- /dev/null
+++ b/src/share/utf8/charset_test.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "charset.h"
+
+void test_any(struct charset *charset)
+{
+  int wc;
+  char s[2];
+
+  assert(charset);
+
+  /* Decoder */
+
+  assert(charset_mbtowc(charset, 0, 0, 0) == 0);
+  assert(charset_mbtowc(charset, 0, 0, 1) == 0);
+  assert(charset_mbtowc(charset, 0, (char *)(-1), 0) == 0);
+
+  assert(charset_mbtowc(charset, 0, "a", 0) == 0);
+  assert(charset_mbtowc(charset, 0, "", 1) == 0);
+  assert(charset_mbtowc(charset, 0, "b", 1) == 1);
+  assert(charset_mbtowc(charset, 0, "", 2) == 0);
+  assert(charset_mbtowc(charset, 0, "c", 2) == 1);
+
+  wc = 'x';
+  assert(charset_mbtowc(charset, &wc, "a", 0) == 0 && wc == 'x');
+  assert(charset_mbtowc(charset, &wc, "", 1) == 0 && wc == 0);
+  assert(charset_mbtowc(charset, &wc, "b", 1) == 1 && wc == 'b');
+  assert(charset_mbtowc(charset, &wc, "", 2) == 0 && wc == 0);
+  assert(charset_mbtowc(charset, &wc, "c", 2) == 1 && wc == 'c');
+
+  /* Encoder */
+
+  assert(charset_wctomb(charset, 0, 0) == 0);
+
+  s[0] = s[1] = '.';
+  assert(charset_wctomb(charset, s, 0) == 1 &&
+	 s[0] == '\0' && s[1] == '.');
+  assert(charset_wctomb(charset, s, 'x') == 1 &&
+	 s[0] == 'x' && s[1] == '.');
+}
+
+void test_utf8()
+{
+  struct charset *charset;
+  int wc;
+  char s[8];
+
+  charset = charset_find("UTF-8");
+  test_any(charset);
+
+  /* Decoder */
+  wc = 0;
+  assert(charset_mbtowc(charset, &wc, "\177", 1) == 1 && wc == 127);
+  assert(charset_mbtowc(charset, &wc, "\200", 2) == -1);
+  assert(charset_mbtowc(charset, &wc, "\301\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\302\200", 1) == -1);
+  assert(charset_mbtowc(charset, &wc, "\302\200", 2) == 2 && wc == 128);
+  assert(charset_mbtowc(charset, &wc, "\302\200", 3) == 2 && wc == 128);
+  assert(charset_mbtowc(charset, &wc, "\340\237\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\240\200", 9) == 3 &&
+	 wc == 1 << 11);
+  assert(charset_mbtowc(charset, &wc, "\360\217\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\200\200", 9) == 4 &&
+	 wc == 1 << 16);
+  assert(charset_mbtowc(charset, &wc, "\370\207\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\370\210\200\200\200", 9) == 5 &&
+	 wc == 1 << 21);
+  assert(charset_mbtowc(charset, &wc, "\374\203\277\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\374\204\200\200\200\200", 9) == 6 &&
+	 wc == 1 << 26);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\277", 9) == 6 &&
+	 wc == 0x7fffffff);
+
+  assert(charset_mbtowc(charset, &wc, "\302\000", 2) == -1);
+  assert(charset_mbtowc(charset, &wc, "\302\300", 2) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\040\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\340\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\240\000", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\240\300", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\020\200\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\320\200\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\000\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\300\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\200\000", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\200\300", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\077\277\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\377\277\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\077\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\377\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\077\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\377\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\077", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\377", 9) == -1);
+
+  assert(charset_mbtowc(charset, &wc, "\376\277\277\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\377\277\277\277\277\277", 9) == -1);
+
+  /* Encoder */
+  safe_strncpy(s, ".......", sizeof(s));
+  assert(charset_wctomb(charset, s, 1u << 31) == -1 &&
+	 !strcmp(s, "......."));
+  assert(charset_wctomb(charset, s, 127) == 1 &&
+	 !strcmp(s, "\177......"));
+  assert(charset_wctomb(charset, s, 128) == 2 &&
+	 !strcmp(s, "\302\200....."));
+  assert(charset_wctomb(charset, s, 0x7ff) == 2 &&
+	 !strcmp(s, "\337\277....."));
+  assert(charset_wctomb(charset, s, 0x800) == 3 &&
+	 !strcmp(s, "\340\240\200...."));
+  assert(charset_wctomb(charset, s, 0xffff) == 3 &&
+	 !strcmp(s, "\357\277\277...."));
+  assert(charset_wctomb(charset, s, 0x10000) == 4 &&
+	 !strcmp(s, "\360\220\200\200..."));
+  assert(charset_wctomb(charset, s, 0x1fffff) == 4 &&
+	 !strcmp(s, "\367\277\277\277..."));
+  assert(charset_wctomb(charset, s, 0x200000) == 5 &&
+	 !strcmp(s, "\370\210\200\200\200.."));
+  assert(charset_wctomb(charset, s, 0x3ffffff) == 5 &&
+	 !strcmp(s, "\373\277\277\277\277.."));
+  assert(charset_wctomb(charset, s, 0x4000000) == 6 &&
+	 !strcmp(s, "\374\204\200\200\200\200."));
+  assert(charset_wctomb(charset, s, 0x7fffffff) == 6 &&
+	 !strcmp(s, "\375\277\277\277\277\277."));
+}
+
+void test_ascii()
+{
+  struct charset *charset;
+  int wc;
+  char s[3];
+
+  charset = charset_find("us-ascii");
+  test_any(charset);
+
+  /* Decoder */
+  wc = 0;
+  assert(charset_mbtowc(charset, &wc, "\177", 2) == 1 && wc == 127);
+  assert(charset_mbtowc(charset, &wc, "\200", 2) == -1);
+
+  /* Encoder */
+  safe_strncpy(s, "..", sizeof(s));
+  assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+  assert(charset_wctomb(charset, s, 255) == -1);
+  assert(charset_wctomb(charset, s, 128) == -1);
+  assert(charset_wctomb(charset, s, 127) == 1 && !strcmp(s, "\177."));
+}
+
+void test_iso1()
+{
+  struct charset *charset;
+  int wc;
+  char s[3];
+
+  charset = charset_find("iso-8859-1");
+  test_any(charset);
+
+  /* Decoder */
+  wc = 0;
+  assert(charset_mbtowc(charset, &wc, "\302\200", 9) == 1 && wc == 0xc2);
+
+  /* Encoder */
+  safe_strncpy(s, "..", sizeof(s));
+  assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+  assert(charset_wctomb(charset, s, 255) == 1 && !strcmp(s, "\377."));
+  assert(charset_wctomb(charset, s, 128) == 1 && !strcmp(s, "\200."));
+}
+
+void test_iso2()
+{
+  struct charset *charset;
+  int wc;
+  char s[3];
+
+  charset = charset_find("iso-8859-2");
+  test_any(charset);
+
+  /* Decoder */
+  wc = 0;
+  assert(charset_mbtowc(charset, &wc, "\302\200", 9) == 1 && wc == 0xc2);
+  assert(charset_mbtowc(charset, &wc, "\377", 2) == 1 && wc == 0x2d9);
+
+  /* Encoder */
+  safe_strncpy(s, "..", sizeof(s));
+  assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+  assert(charset_wctomb(charset, s, 255) == -1 && !strcmp(s, ".."));
+  assert(charset_wctomb(charset, s, 258) == 1 && !strcmp(s, "\303."));
+  assert(charset_wctomb(charset, s, 128) == 1 && !strcmp(s, "\200."));
+}
+
+void test_convert()
+{
+  const char *p;
+  char *q, *r;
+  char s[256];
+  size_t n, n2;
+  int i;
+
+  p = "\000x\302\200\375\277\277\277\277\277";
+  assert(charset_convert("UTF-8", "UTF-8", p, 10, &q, &n) == 0 &&
+	 n == 10 && !strcmp(p, q));
+  assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, &q, &n) == 2 &&
+	 n == 4 && !strcmp(q, "x##y"));
+  assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, 0, &n) == 2 &&
+	 n == 4);
+  assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, &q, 0) == 2 &&
+	 !strcmp(q, "x##y"));
+  assert(charset_convert("UTF-8", "iso-8859-1",
+			 "\302\200\304\200x", 5, &q, &n) == 1 &&
+	 n == 3 && !strcmp(q, "\200?x"));
+  assert(charset_convert("iso-8859-1", "UTF-8",
+			 "\000\200\377", 3, &q, &n) == 0 &&
+	 n == 5 && !memcmp(q, "\000\302\200\303\277", 5));
+  assert(charset_convert("iso-8859-1", "iso-8859-1",
+			 "\000\200\377", 3, &q, &n) == 0 &&
+	 n == 3 && !memcmp(q, "\000\200\377", 3));
+
+  assert(charset_convert("iso-8859-2", "utf-8", "\300", 1, &q, &n) == 0 &&
+	 n == 2 && !strcmp(q, "\305\224"));
+  assert(charset_convert("utf-8", "iso-8859-2", "\305\224", 2, &q, &n) == 0 &&
+	 n == 1 && !strcmp(q, "\300"));
+
+  for (i = 0; i < 256; i++)
+    s[i] = i;
+
+  assert(charset_convert("iso-8859-2", "utf-8", s, 256, &q, &n) == 0);
+  assert(charset_convert("utf-8", "iso-8859-2", q, n, &r, &n2) == 0);
+  assert(n2 == 256 && !memcmp(r, s, n2));
+}
+
+int main()
+{
+  test_utf8();
+  test_ascii();
+  test_iso1();
+  test_iso2();
+
+  test_convert();
+
+  return 0;
+}
diff --git a/src/share/utf8/iconvert.c b/src/share/utf8/iconvert.c
new file mode 100644
index 0000000..8ab53c1
--- /dev/null
+++ b/src/share/utf8/iconvert.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if !defined _WIN32 && defined HAVE_ICONV
+
+#include <assert.h>
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "iconvert.h"
+#include "share/alloc.h"
+#include "share/safe_str.h"
+
+/*
+ * Convert data from one encoding to another. Return:
+ *
+ *  -2 : memory allocation failed
+ *  -1 : unknown encoding
+ *   0 : data was converted exactly
+ *   1 : data was converted inexactly
+ *   2 : data was invalid (but still converted)
+ *
+ * We convert in two steps, via UTF-8, as this is the only
+ * reliable way of distinguishing between invalid input
+ * and valid input which iconv refuses to transliterate.
+ * We convert from UTF-8 twice, because we have no way of
+ * knowing whether the conversion was exact if iconv returns
+ * E2BIG (due to a bug in the specification of iconv).
+ * An alternative approach is to assume that the output of
+ * iconv is never more than 4 times as long as the input,
+ * but I prefer to avoid that assumption if possible.
+ */
+
+int iconvert(const char *fromcode, const char *tocode,
+	     const char *from, size_t fromlen,
+	     char **to, size_t *tolen)
+{
+  int ret = 0;
+  iconv_t cd1, cd2;
+  char *ib;
+  char *ob;
+  char *utfbuf = 0, *outbuf, *newbuf;
+  size_t utflen, outlen, ibl, obl, k;
+  char tbuf[2048];
+
+  cd1 = iconv_open("UTF-8", fromcode);
+  if (cd1 == (iconv_t)(-1))
+    return -1;
+
+  cd2 = (iconv_t)(-1);
+  /* Don't use strcasecmp() as it's locale-dependent. */
+  if (!strchr("Uu", tocode[0]) ||
+      !strchr("Tt", tocode[1]) ||
+      !strchr("Ff", tocode[2]) ||
+      tocode[3] != '-' ||
+      tocode[4] != '8' ||
+      tocode[5] != '\0') {
+    char *tocode1;
+    int rc;
+    /*
+     * Try using this non-standard feature of glibc and libiconv.
+     * This is deliberately not a config option as people often
+     * change their iconv library without rebuilding applications.
+     */
+
+    rc = asprintf(&tocode1, "%s//TRANSLIT", tocode);
+    if (rc < 0 || ! tocode1)
+      goto fail;
+
+    cd2 = iconv_open(tocode1, "UTF-8");
+    free(tocode1);
+
+    if (cd2 == (iconv_t)(-1))
+      cd2 = iconv_open(tocode, fromcode);
+
+    if (cd2 == (iconv_t)(-1)) {
+      iconv_close(cd1);
+      return -1;
+    }
+  }
+
+  utflen = 1; /*fromlen * 2 + 1; XXX */
+  utfbuf = malloc(utflen);
+  if (!utfbuf)
+    goto fail;
+
+  /* Convert to UTF-8 */
+  ib = (char *)from;
+  ibl = fromlen;
+  ob = utfbuf;
+  obl = utflen;
+  for (;;) {
+    k = iconv(cd1, &ib, &ibl, &ob, &obl);
+    assert((!k && !ibl) ||
+	   (k == (size_t)(-1) && errno == E2BIG && ibl && obl < 6) ||
+	   (k == (size_t)(-1) &&
+	    (errno == EILSEQ || errno == EINVAL) && ibl));
+    if (!ibl)
+      break;
+    if (obl < 6) {
+      /* Enlarge the buffer */
+      if(utflen*2 < utflen) /* overflow check */
+	goto fail;
+      utflen *= 2;
+      newbuf = realloc(utfbuf, utflen);
+      if (!newbuf)
+	goto fail;
+      ob = (ob - utfbuf) + newbuf;
+      obl = utflen - (ob - newbuf);
+      utfbuf = newbuf;
+    }
+    else {
+      /* Invalid input */
+      ib++, ibl--;
+      *ob++ = '#', obl--;
+      ret = 2;
+      iconv(cd1, 0, 0, 0, 0);
+    }
+  }
+
+  if (cd2 == (iconv_t)(-1)) {
+    /* The target encoding was UTF-8 */
+    if (tolen)
+      *tolen = ob - utfbuf;
+    if (!to) {
+      free(utfbuf);
+      iconv_close(cd1);
+      return ret;
+    }
+    newbuf = safe_realloc_add_2op_(utfbuf, (ob - utfbuf), /*+*/1);
+    if (!newbuf)
+      goto fail;
+    ob = (ob - utfbuf) + newbuf;
+    *ob = '\0';
+    *to = newbuf;
+    iconv_close(cd1);
+    return ret;
+  }
+
+  /* Truncate the buffer to be tidy */
+  utflen = ob - utfbuf;
+  newbuf = realloc(utfbuf, utflen);
+  if (!newbuf)
+    goto fail;
+  utfbuf = newbuf;
+
+  /* Convert from UTF-8 to discover how long the output is */
+  outlen = 0;
+  ib = utfbuf;
+  ibl = utflen;
+  while (ibl) {
+    ob = tbuf;
+    obl = sizeof(tbuf);
+    k = iconv(cd2, &ib, &ibl, &ob, &obl);
+    assert((k != (size_t)(-1) && !ibl) ||
+	   (k == (size_t)(-1) && errno == E2BIG && ibl) ||
+	   (k == (size_t)(-1) && errno == EILSEQ && ibl));
+    if (ibl && !(k == (size_t)(-1) && errno == E2BIG)) {
+      /* Replace one character */
+      char *tb = "?";
+      size_t tbl = 1;
+
+      outlen += ob - tbuf;
+      ob = tbuf;
+      obl = sizeof(tbuf);
+      k = iconv(cd2, &tb, &tbl, &ob, &obl);
+      assert((!k && !tbl) ||
+	     (k == (size_t)(-1) && errno == EILSEQ && tbl));
+      for (++ib, --ibl; ibl && (*ib & 0x80); ib++, ibl--)
+	;
+    }
+    outlen += ob - tbuf;
+  }
+  ob = tbuf;
+  obl = sizeof(tbuf);
+  k = iconv(cd2, 0, 0, &ob, &obl);
+  assert(!k);
+  outlen += ob - tbuf;
+
+  /* Convert from UTF-8 for real */
+  outbuf = safe_malloc_add_2op_(outlen, /*+*/1);
+  if (!outbuf)
+    goto fail;
+  ib = utfbuf;
+  ibl = utflen;
+  ob = outbuf;
+  obl = outlen;
+  while (ibl) {
+    k = iconv(cd2, &ib, &ibl, &ob, &obl);
+    assert((k != (size_t)(-1) && !ibl) ||
+	   (k == (size_t)(-1) && errno == EILSEQ && ibl));
+    if (k && !ret)
+      ret = 1;
+    if (ibl && !(k == (size_t)(-1) && errno == E2BIG)) {
+      /* Replace one character */
+      char *tb = "?";
+      size_t tbl = 1;
+
+      k = iconv(cd2, &tb, &tbl, &ob, &obl);
+      assert((!k && !tbl) ||
+	     (k == (size_t)(-1) && errno == EILSEQ && tbl));
+      for (++ib, --ibl; ibl && (*ib & 0x80); ib++, ibl--)
+	;
+    }
+  }
+  k = iconv(cd2, 0, 0, &ob, &obl);
+  assert(!k);
+  assert(!obl);
+  *ob = '\0';
+
+  free(utfbuf);
+  iconv_close(cd1);
+  iconv_close(cd2);
+  if (tolen)
+    *tolen = outlen;
+  if (!to) {
+    free(outbuf);
+    return ret;
+  }
+  *to = outbuf;
+  return ret;
+
+ fail:
+  if(0 != utfbuf)
+    free(utfbuf);
+  iconv_close(cd1);
+  if (cd2 != (iconv_t)(-1))
+    iconv_close(cd2);
+  return -2;
+}
+
+#endif /* HAVE_ICONV */
diff --git a/src/share/utf8/iconvert.h b/src/share/utf8/iconvert.h
new file mode 100644
index 0000000..a2d75a2
--- /dev/null
+++ b/src/share/utf8/iconvert.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef HAVE_ICONV
+
+/*
+ * Convert data from one encoding to another. Return:
+ *
+ *  -2 : memory allocation failed
+ *  -1 : unknown encoding
+ *   0 : data was converted exactly
+ *   1 : data was converted inexactly
+ *   2 : data was invalid (but still converted)
+ *
+ * We convert in two steps, via UTF-8, as this is the only
+ * reliable way of distinguishing between invalid input
+ * and valid input which iconv refuses to transliterate.
+ * We convert from UTF-8 twice, because we have no way of
+ * knowing whether the conversion was exact if iconv returns
+ * E2BIG (due to a bug in the specification of iconv).
+ * An alternative approach is to assume that the output of
+ * iconv is never more than 4 times as long as the input,
+ * but I prefer to avoid that assumption if possible.
+ */
+
+int iconvert(const char *fromcode, const char *tocode,
+	     const char *from, size_t fromlen,
+	     char **to, size_t *tolen) ;
+
+#endif /* HAVE_ICONV */
diff --git a/src/share/utf8/makemap.c b/src/share/utf8/makemap.c
new file mode 100644
index 0000000..790021c
--- /dev/null
+++ b/src/share/utf8/makemap.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+  iconv_t cd;
+  const char *ib;
+  char *ob;
+  size_t ibl, obl, k;
+  uint8_t c, buf[4];
+  int i, wc;
+
+  if (argc != 2) {
+    printf("Usage: %s ENCODING\n", argv[0]);
+    printf("Output a charset map for the 8-bit ENCODING.\n");
+    return 1;
+  }
+
+  cd = iconv_open("UCS-4", argv[1]);
+  if (cd == (iconv_t)(-1)) {
+    perror("iconv_open");
+    return 1;
+  }
+
+  for (i = 0; i < 256; i++) {
+    c = i;
+    ib = &c;
+    ibl = 1;
+    ob = buf;
+    obl = 4;
+    k = iconv(cd, &ib, &ibl, &ob, &obl);
+    if (!k && !ibl && !obl) {
+      wc = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+      if (wc >= 0xffff) {
+	printf("Dodgy value.\n");
+	return 1;
+      }
+    }
+    else if (k == (size_t)(-1) && errno == EILSEQ)
+      wc = 0xffff;
+    else {
+      printf("Non-standard iconv.\n");
+      return 1;
+    }
+
+    if (i % 8 == 0)
+      printf("  ");
+    printf("0x%04x", wc);
+    if (i == 255)
+      printf("\n");
+    else if (i % 8 == 7)
+      printf(",\n");
+    else
+      printf(", ");
+  }
+
+  return 0;
+}
diff --git a/src/share/utf8/utf8.c b/src/share/utf8/utf8.c
new file mode 100644
index 0000000..34af187
--- /dev/null
+++ b/src/share/utf8/utf8.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * Buffer overflow checking added: Josh Coalson, 9/9/2007
+ *
+ * Win32 part rewritten: lvqcl, 2/2/2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "share/alloc.h"
+#include "share/utf8.h"
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+int utf8_encode(const char *from, char **to)
+{
+	wchar_t *unicode = NULL;
+	char *utf8 = NULL;
+	int ret = -1;
+
+	do {
+		int len;
+
+		len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, -1, NULL, 0);
+		if(len == 0) break;
+		unicode = (wchar_t*) safe_malloc_mul_2op_((size_t)len, sizeof(wchar_t));
+		if(unicode == NULL) break;
+		len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, -1, unicode, len);
+		if(len == 0) break;
+
+		len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL);
+		if(len == 0) break;
+		utf8 = (char*) safe_malloc_mul_2op_((size_t)len, sizeof(char));
+		if(utf8 == NULL) break;
+		len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len, NULL, NULL);
+		if(len == 0) break;
+
+		ret = 0;
+
+	} while(0);
+
+	free(unicode);
+
+	if(ret == 0) {
+		*to = utf8;
+	} else {
+		free(utf8);
+		*to = NULL;
+	}
+
+	return ret;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+	wchar_t *unicode = NULL;
+	char *acp = NULL;
+	int ret = -1;
+
+	do {
+		int len;
+
+		len = MultiByteToWideChar(CP_UTF8, 0, from, -1, NULL, 0);
+		if(len == 0) break;
+		unicode = (wchar_t*) safe_malloc_mul_2op_((size_t)len, sizeof(wchar_t));
+		if(unicode == NULL) break;
+		len = MultiByteToWideChar(CP_UTF8, 0, from, -1, unicode, len);
+		if(len == 0) break;
+
+		len = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+		if(len == 0) break;
+		acp = (char*) safe_malloc_mul_2op_((size_t)len, sizeof(char));
+		if(acp == NULL) break;
+		len = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, acp, len, NULL, NULL);
+		if(len == 0) break;
+
+		ret = 0;
+
+	} while(0);
+
+	free(unicode);
+
+	if(ret == 0) {
+		*to = acp;
+	} else {
+		free(acp);
+		*to = NULL;
+	}
+
+	return ret;
+}
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include <string.h>
+
+#include "share/safe_str.h"
+#include "iconvert.h"
+#include "charset.h"
+
+static const char *current_charset(void)
+{
+  const char *c = 0;
+#ifdef HAVE_LANGINFO_CODESET
+  c = nl_langinfo(CODESET);
+#endif
+
+  if (!c)
+    c = getenv("CHARSET");
+
+  return c? c : "US-ASCII";
+}
+
+static int convert_buffer(const char *fromcode, const char *tocode,
+			  const char *from, size_t fromlen,
+			  char **to, size_t *tolen)
+{
+  int ret = -1;
+
+#ifdef HAVE_ICONV
+  ret = iconvert(fromcode, tocode, from, fromlen, to, tolen);
+  if (ret != -1)
+    return ret;
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+  ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen);
+  if (ret != -1)
+    return ret;
+#endif
+
+  return ret;
+}
+
+static int convert_string(const char *fromcode, const char *tocode,
+			  const char *from, char **to, char replace)
+{
+  int ret;
+  size_t fromlen;
+  char *s;
+
+  fromlen = strlen(from);
+  ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0);
+  if (ret == -2)
+    return -1;
+  if (ret != -1)
+    return ret;
+
+  s = safe_malloc_add_2op_(fromlen, /*+*/1);
+  if (!s)
+    return -1;
+  snprintf(s, fromlen + 1, "%s", from);
+  *to = s;
+  for (; *s; s++)
+    if (*s & ~0x7f)
+      *s = replace;
+  return 3;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+  return convert_string(current_charset(), "UTF-8", from, to, '#');
+}
+
+int utf8_decode(const char *from, char **to)
+{
+  return convert_string("UTF-8", current_charset(), from, to, '?');
+}
+
+#endif
diff --git a/src/share/utf8/utf8_static.vcproj b/src/share/utf8/utf8_static.vcproj
new file mode 100644
index 0000000..45a031a
--- /dev/null
+++ b/src/share/utf8/utf8_static.vcproj
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="utf8_static"

+	ProjectGUID="{4cefbc92-c215-11db-8314-0800200c9a66}"

+	RootNamespace="utf8_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\..\include\share\utf8.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\utf8.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/share/utf8/utf8_static.vcxproj b/src/share/utf8/utf8_static.vcxproj
new file mode 100644
index 0000000..5298e92
--- /dev/null
+++ b/src/share/utf8/utf8_static.vcxproj
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc92-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>utf8_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\utf8.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="utf8.c" />

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/utf8/utf8_static.vcxproj.filters b/src/share/utf8/utf8_static.vcxproj.filters
new file mode 100644
index 0000000..dfbaa99
--- /dev/null
+++ b/src/share/utf8/utf8_static.vcxproj.filters
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{c96e2c5d-a952-4c1d-b3d7-294a5b216154}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\utf8.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="utf8.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/win_utf8_io/Makefile.lite b/src/share/win_utf8_io/Makefile.lite
new file mode 100644
index 0000000..1549266
--- /dev/null
+++ b/src/share/win_utf8_io/Makefile.lite
@@ -0,0 +1,21 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lFLAC $(OGG_LIBS) -lm
+endif
+
+LIB_NAME = libwin_utf8_io
+INCLUDES = -I$(topdir)/include
+
+SRCS_C = \
+	win_utf8_io.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/win_utf8_io/win_utf8_io.c b/src/share/win_utf8_io/win_utf8_io.c
new file mode 100644
index 0000000..bbb6a74
--- /dev/null
+++ b/src/share/win_utf8_io/win_utf8_io.c
@@ -0,0 +1,271 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016  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 <windows.h>
+#include "share/win_utf8_io.h"
+#include "share/windows_unicode_filenames.h"
+
+#define UTF8_BUFFER_SIZE 32768
+
+static int local_vsnprintf(char *str, size_t size, const char *fmt, va_list va)
+{
+	int rc;
+
+#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
+
+	return rc;
+}
+
+/* convert WCHAR stored Unicode string to UTF-8. Caller is responsible for freeing memory */
+static char *utf8_from_wchar(const wchar_t *wstr)
+{
+	char *utf8str;
+	int len;
+
+	if (!wstr)
+		return NULL;
+	if ((len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL)) == 0)
+		return NULL;
+	if ((utf8str = (char *)malloc(len)) == NULL)
+		return NULL;
+	if (WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8str, len, NULL, NULL) == 0) {
+		free(utf8str);
+		utf8str = NULL;
+	}
+
+	return utf8str;
+}
+
+/* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */
+static wchar_t *wchar_from_utf8(const char *str)
+{
+	wchar_t *widestr;
+	int len;
+
+	if (!str)
+		return NULL;
+	if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0)
+		return NULL;
+	if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) == NULL)
+		return NULL;
+	if (MultiByteToWideChar(CP_UTF8, 0, str, -1, widestr, len) == 0) {
+		free(widestr);
+		widestr = NULL;
+	}
+
+	return widestr;
+}
+
+/* retrieve WCHAR commandline, expand wildcards and convert everything to UTF-8 */
+int get_utf8_argv(int *argc, char ***argv)
+{
+	typedef int (__cdecl *wgetmainargs_t)(int*, wchar_t***, wchar_t***, int, int*);
+	wgetmainargs_t wgetmainargs;
+	HMODULE handle;
+	int wargc;
+	wchar_t **wargv;
+	wchar_t **wenv;
+	char **utf8argv;
+	int ret, i;
+
+	if ((handle = LoadLibraryW(L"msvcrt.dll")) == NULL) return 1;
+	if ((wgetmainargs = (wgetmainargs_t)GetProcAddress(handle, "__wgetmainargs")) == NULL) {
+		FreeLibrary(handle);
+		return 1;
+	}
+	i = 0;
+	/* when the 4th argument is 1,  __wgetmainargs expands wildcards but also erroneously converts \\?\c:\path\to\file.flac to \\file.flac */
+	if (wgetmainargs(&wargc, &wargv, &wenv, 1, &i) != 0) {
+		FreeLibrary(handle);
+		return 1;
+	}
+	if ((utf8argv = (char **)calloc(wargc, sizeof(char*))) == NULL) {
+		FreeLibrary(handle);
+		return 1;
+	}
+
+	ret = 0;
+	for (i=0; i<wargc; i++) {
+		if ((utf8argv[i] = utf8_from_wchar(wargv[i])) == NULL) {
+			ret = 1;
+			break;
+		}
+	}
+
+	FreeLibrary(handle); /* do not free it when wargv or wenv are still in use */
+
+	if (ret == 0) {
+		flac_set_utf8_filenames(true);
+		*argc = wargc;
+		*argv = utf8argv;
+	} else {
+		for (i=0; i<wargc; i++)
+			free(utf8argv[i]);
+		free(utf8argv);
+	}
+
+	return ret;
+}
+
+/* similar to CreateFileW but accepts UTF-8 encoded lpFileName */
+HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
+{
+	if (!flac_internal_get_utf8_filenames()) {
+		return CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+	} else {
+		wchar_t *wname;
+		HANDLE handle = INVALID_HANDLE_VALUE;
+
+		if ((wname = wchar_from_utf8(lpFileName)) != NULL) {
+			handle = CreateFileW(wname, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+			free(wname);
+		}
+
+		return handle;
+	}
+}
+
+/* return number of characters in the UTF-8 string */
+size_t strlen_utf8(const char *str)
+{
+	size_t len;
+	len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); /* includes terminating null */
+	if (len != 0)
+		return len-1;
+	else
+		return strlen(str);
+}
+
+/* get the console width in characters */
+int win_get_console_width(void)
+{
+	int width = 80;
+	CONSOLE_SCREEN_BUFFER_INFO csbi;
+	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+	if(hOut != INVALID_HANDLE_VALUE && hOut != NULL)
+		if (GetConsoleScreenBufferInfo(hOut, &csbi) != 0)
+			width = csbi.dwSize.X;
+	return width;
+}
+
+/* print functions */
+
+static int wprint_console(FILE *stream, const wchar_t *text, size_t len)
+{
+	DWORD out;
+	int ret;
+
+	do {
+		if (stream == stdout) {
+			HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+			if (hOut == INVALID_HANDLE_VALUE || hOut == NULL || GetFileType(hOut) != FILE_TYPE_CHAR)
+				break;
+			if (WriteConsoleW(hOut, text, len, &out, NULL) == 0)
+				return -1;
+			return out;
+		}
+		if (stream == stderr) {
+			HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE);
+			if (hErr == INVALID_HANDLE_VALUE || hErr == NULL || GetFileType(hErr) != FILE_TYPE_CHAR)
+				break;
+			if (WriteConsoleW(hErr, text, len, &out, NULL) == 0)
+				return -1;
+			return out;
+		}
+	} while(0);
+
+	ret = fputws(text, stream);
+	if (ret < 0)
+		return ret;
+	return len;
+}
+
+int printf_utf8(const char *format, ...)
+{
+	int ret;
+	va_list argptr;
+	va_start(argptr, format);
+
+	ret = vfprintf_utf8(stdout, format, argptr);
+
+	va_end(argptr);
+
+	return ret;
+}
+
+int fprintf_utf8(FILE *stream, const char *format, ...)
+{
+	int ret;
+	va_list argptr;
+	va_start(argptr, format);
+
+	ret = vfprintf_utf8(stream, format, argptr);
+
+	va_end(argptr);
+
+	return ret;
+}
+
+int vfprintf_utf8(FILE *stream, const char *format, va_list argptr)
+{
+	char *utmp = NULL;
+	wchar_t *wout = NULL;
+	int ret = -1;
+
+	do {
+		if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE))) break;
+		if ((ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr)) <= 0) break;
+		if (!(wout = wchar_from_utf8(utmp))) {
+			ret = -1;
+			break;
+		}
+		ret = wprint_console(stream, wout, wcslen(wout));
+	} while(0);
+
+	free(utmp);
+	free(wout);
+
+	return ret;
+}
diff --git a/src/share/win_utf8_io/win_utf8_io_static.vcproj b/src/share/win_utf8_io/win_utf8_io_static.vcproj
new file mode 100644
index 0000000..b34cbbe
--- /dev/null
+++ b/src/share/win_utf8_io/win_utf8_io_static.vcproj
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="win_utf8_io_static"

+	ProjectGUID="{4cefbe02-c215-11db-8314-0800200c9a66}"

+	RootNamespace="win_utf8_io_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Public Header Files"

+			>

+			<File

+				RelativePath="..\..\..\include\share\win_utf8_io.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\win_utf8_io.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/share/win_utf8_io/win_utf8_io_static.vcxproj b/src/share/win_utf8_io/win_utf8_io_static.vcxproj
new file mode 100644
index 0000000..aa9a3ee
--- /dev/null
+++ b/src/share/win_utf8_io/win_utf8_io_static.vcxproj
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbe02-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>win_utf8_io_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\win_utf8_io.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="win_utf8_io.c" />

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/share/win_utf8_io/win_utf8_io_static.vcxproj.filters b/src/share/win_utf8_io/win_utf8_io_static.vcxproj.filters
new file mode 100644
index 0000000..e44a0c7
--- /dev/null
+++ b/src/share/win_utf8_io/win_utf8_io_static.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Public Header Files">

+      <UniqueIdentifier>{6469e7f2-0837-4004-9f36-27d45ed62336}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\..\include\share\win_utf8_io.h">

+      <Filter>Public Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="win_utf8_io.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_grabbag/CMakeLists.txt b/src/test_grabbag/CMakeLists.txt
new file mode 100644
index 0000000..56abe81
--- /dev/null
+++ b/src/test_grabbag/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(cuesheet)
+add_subdirectory(picture)
diff --git a/src/test_grabbag/Makefile.am b/src/test_grabbag/Makefile.am
new file mode 100644
index 0000000..c13ca3b
--- /dev/null
+++ b/src/test_grabbag/Makefile.am
@@ -0,0 +1,23 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = cuesheet picture
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite
diff --git a/src/test_grabbag/Makefile.lite b/src/test_grabbag/Makefile.lite
new file mode 100644
index 0000000..a0e4447
--- /dev/null
+++ b/src/test_grabbag/Makefile.lite
@@ -0,0 +1,41 @@
+#  test_grabbag - Simple testers for the grabbag library
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+.PHONY: cuesheet picture
+all: cuesheet picture
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+cuesheet:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+picture:
+	(cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+clean:
+	-(cd cuesheet ; $(MAKE) -f Makefile.lite clean)
+	-(cd picture ; $(MAKE) -f Makefile.lite clean)
diff --git a/src/test_grabbag/cuesheet/CMakeLists.txt b/src/test_grabbag/cuesheet/CMakeLists.txt
new file mode 100644
index 0000000..5f9a646
--- /dev/null
+++ b/src/test_grabbag/cuesheet/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(test_cuesheet
+    main.c
+    $<$<BOOL:${WIN32}>:../../../include/share/win_utf8_io.h>
+    $<$<BOOL:${WIN32}>:../../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(test_cuesheet FLAC grabbag)
diff --git a/src/test_grabbag/cuesheet/Makefile.am b/src/test_grabbag/cuesheet/Makefile.am
new file mode 100644
index 0000000..6b88be4
--- /dev/null
+++ b/src/test_grabbag/cuesheet/Makefile.am
@@ -0,0 +1,35 @@
+#  test_cuesheet - Simple tester for cuesheet routines in grabbag
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	test_cuesheet.vcproj \
+	test_cuesheet.vcxproj \
+	test_cuesheet.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+check_PROGRAMS = test_cuesheet
+test_cuesheet_SOURCES = \
+	main.c
+test_cuesheet_LDADD = \
+	$(top_builddir)/src/share/grabbag/libgrabbag.la \
+	$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+	$(top_builddir)/src/libFLAC/libFLAC.la
+
+CLEANFILES = test_cuesheet.exe
diff --git a/src/test_grabbag/cuesheet/Makefile.lite b/src/test_grabbag/cuesheet/Makefile.lite
new file mode 100644
index 0000000..e66d10b
--- /dev/null
+++ b/src/test_grabbag/cuesheet/Makefile.lite
@@ -0,0 +1,43 @@
+#  test_cuesheet - Simple tester for cuesheet routines in grabbag
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = test_cuesheet
+
+INCLUDES = -I./include -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lgrabbag -lreplaygain_analysis -lFLAC $(OGG_LIBS) -lm
+endif
+
+SRCS_C = \
+	main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_grabbag/cuesheet/main.c b/src/test_grabbag/cuesheet/main.c
new file mode 100644
index 0000000..433d11a
--- /dev/null
+++ b/src/test_grabbag/cuesheet/main.c
@@ -0,0 +1,147 @@
+/* test_cuesheet - Simple tester for cuesheet routines in grabbag
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+
+static int do_cuesheet(const char *infilename, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+	FILE *fin, *fout;
+	const char *error_message, *tmpfilenamebase;
+	char tmpfilename[4096];
+	uint32_t last_line_read;
+	FLAC__StreamMetadata *cuesheet;
+
+	FLAC__ASSERT(strlen(infilename) + 2 < sizeof(tmpfilename));
+
+	/*
+	 * pass 1
+	 */
+	if(0 == strcmp(infilename, "-")) {
+		fin = stdin;
+	}
+	else if(0 == (fin = flac_fopen(infilename, "r"))) {
+		fprintf(stderr, "can't open file %s for reading: %s\n", infilename, strerror(errno));
+		return 255;
+	}
+	if(0 != (cuesheet = grabbag__cuesheet_parse(fin, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset))) {
+		if(fin != stdin)
+			fclose(fin);
+	}
+	else {
+		printf("pass1: parse error, line %u: \"%s\"\n", last_line_read, error_message);
+		if(fin != stdin)
+			fclose(fin);
+		return 1;
+	}
+	if(!FLAC__metadata_object_cuesheet_is_legal(cuesheet, is_cdda, &error_message)) {
+		printf("pass1: illegal cuesheet: \"%s\"\n", error_message);
+		FLAC__metadata_object_delete(cuesheet);
+		return 1;
+	}
+
+	tmpfilenamebase = strstr(infilename, "cuesheets/");
+	tmpfilenamebase = tmpfilenamebase == NULL ? infilename : tmpfilenamebase;
+
+	flac_snprintf(tmpfilename, sizeof (tmpfilename), "%s.1", tmpfilenamebase);
+	if(0 == (fout = flac_fopen(tmpfilename, "w"))) {
+		fprintf(stderr, "can't open file %s for writing: %s\n", tmpfilename, strerror(errno));
+		FLAC__metadata_object_delete(cuesheet);
+		return 255;
+	}
+	grabbag__cuesheet_emit(fout, cuesheet, "\"dummy.wav\" WAVE");
+	FLAC__metadata_object_delete(cuesheet);
+	fclose(fout);
+
+	/*
+	 * pass 2
+	 */
+	if(0 == (fin = flac_fopen(tmpfilename, "r"))) {
+		fprintf(stderr, "can't open file %s for reading: %s\n", tmpfilename, strerror(errno));
+		return 255;
+	}
+	if(0 != (cuesheet = grabbag__cuesheet_parse(fin, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset))) {
+		if(fin != stdin)
+			fclose(fin);
+	}
+	else {
+		printf("pass2: parse error, line %u: \"%s\"\n", last_line_read, error_message);
+		if(fin != stdin)
+			fclose(fin);
+		return 1;
+	}
+	if(!FLAC__metadata_object_cuesheet_is_legal(cuesheet, is_cdda, &error_message)) {
+		printf("pass2: illegal cuesheet: \"%s\"\n", error_message);
+		FLAC__metadata_object_delete(cuesheet);
+		return 1;
+	}
+	flac_snprintf(tmpfilename, sizeof (tmpfilename), "%s.2", tmpfilenamebase);
+	if(0 == (fout = flac_fopen(tmpfilename, "w"))) {
+		fprintf(stderr, "can't open file %s for writing: %s\n", tmpfilename, strerror(errno));
+		FLAC__metadata_object_delete(cuesheet);
+		return 255;
+	}
+	grabbag__cuesheet_emit(fout, cuesheet, "\"dummy.wav\" WAVE");
+	FLAC__metadata_object_delete(cuesheet);
+	fclose(fout);
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	FLAC__uint64 lead_out_offset;
+	uint32_t sample_rate = 48000;
+	FLAC__bool is_cdda = false;
+	const char *usage = "usage: test_cuesheet cuesheet_file lead_out_offset [ [ sample_rate ] cdda ]\n";
+
+	if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+		puts(usage);
+		return 0;
+	}
+
+	if(argc < 3 || argc > 5) {
+		fputs(usage, stderr);
+		return 255;
+	}
+
+	lead_out_offset = (FLAC__uint64)strtoul(argv[2], 0, 10);
+	if(argc >= 4) {
+		sample_rate = (uint32_t)atoi(argv[3]);
+		if(argc >= 5) {
+			if(0 == strcmp(argv[4], "cdda"))
+				is_cdda = true;
+			else {
+				fputs(usage, stderr);
+				return 255;
+			}
+		}
+	}
+
+	return do_cuesheet(argv[1], sample_rate, is_cdda, lead_out_offset);
+}
diff --git a/src/test_grabbag/cuesheet/test_cuesheet.vcproj b/src/test_grabbag/cuesheet/test_cuesheet.vcproj
new file mode 100644
index 0000000..cf0f4d9
--- /dev/null
+++ b/src/test_grabbag/cuesheet/test_cuesheet.vcproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="test_cuesheet"

+	ProjectGUID="{4cefbc8b-c215-11db-8314-0800200c9a66}"

+	RootNamespace="test_cuesheet"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/test_grabbag/cuesheet/test_cuesheet.vcxproj b/src/test_grabbag/cuesheet/test_cuesheet.vcxproj
new file mode 100644
index 0000000..301fa15
--- /dev/null
+++ b/src/test_grabbag/cuesheet/test_cuesheet.vcxproj
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc8b-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>test_cuesheet</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+    </ProjectReference>

+    <ProjectReference Include="..\..\share\grabbag\grabbag_static.vcxproj">

+      <Project>{4cefbc81-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_grabbag/cuesheet/test_cuesheet.vcxproj.filters b/src/test_grabbag/cuesheet/test_cuesheet.vcxproj.filters
new file mode 100644
index 0000000..5c9040b
--- /dev/null
+++ b/src/test_grabbag/cuesheet/test_cuesheet.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_grabbag/picture/CMakeLists.txt b/src/test_grabbag/picture/CMakeLists.txt
new file mode 100644
index 0000000..77f1a38
--- /dev/null
+++ b/src/test_grabbag/picture/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(test_picture
+    main.c
+    $<$<BOOL:${WIN32}>:../../../include/share/win_utf8_io.h>
+    $<$<BOOL:${WIN32}>:../../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(test_picture FLAC grabbag)
diff --git a/src/test_grabbag/picture/Makefile.am b/src/test_grabbag/picture/Makefile.am
new file mode 100644
index 0000000..36b79f8
--- /dev/null
+++ b/src/test_grabbag/picture/Makefile.am
@@ -0,0 +1,41 @@
+#  test_picture - Simple tester for picture routines in grabbag
+#  Copyright (C) 2006-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	test_picture.vcproj \
+	test_picture.vcxproj \
+	test_picture.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+check_PROGRAMS = test_picture
+test_picture_SOURCES = \
+	main.c
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+test_picture_LDADD = \
+	$(top_builddir)/src/share/grabbag/libgrabbag.la \
+	$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+	$(top_builddir)/src/libFLAC/libFLAC.la \
+	$(win_utf8_lib)
+
+CLEANFILES = test_picture.exe
diff --git a/src/test_grabbag/picture/Makefile.lite b/src/test_grabbag/picture/Makefile.lite
new file mode 100644
index 0000000..2844923
--- /dev/null
+++ b/src/test_grabbag/picture/Makefile.lite
@@ -0,0 +1,47 @@
+#  test_picture - Simple tester for picture routines in grabbag
+#  Copyright (C) 2006-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = test_picture
+
+INCLUDES = -I./include -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+ifeq ($(findstring Windows,$(OS)),Windows)
+    LIBS = -lgrabbag -lreplaygain_analysis -lFLAC -lwin_utf8_io $(OGG_LIBS) -lm
+else
+    LIBS = -lgrabbag -lreplaygain_analysis -lFLAC $(OGG_LIBS) -lm
+endif
+endif
+
+SRCS_C = \
+	main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_grabbag/picture/main.c b/src/test_grabbag/picture/main.c
new file mode 100644
index 0000000..df91409
--- /dev/null
+++ b/src/test_grabbag/picture/main.c
@@ -0,0 +1,222 @@
+/* test_picture - Simple tester for picture routines in grabbag
+ * Copyright (C) 2006-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include "FLAC/assert.h"
+#include "share/grabbag.h"
+
+typedef struct {
+	const char *path;
+	const char *mime_type;
+	const char *description;
+	FLAC__uint32 width;
+	FLAC__uint32 height;
+	FLAC__uint32 depth;
+	FLAC__uint32 colors;
+	FLAC__StreamMetadata_Picture_Type type;
+} PictureFile;
+
+PictureFile picturefiles[] = {
+	{ "0.gif", "image/gif" , "", 24, 24, 24, 2, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "1.gif", "image/gif" , "", 12,  8, 24, 256, FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER },
+	{ "2.gif", "image/gif" , "", 16, 14, 24, 128, FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER },
+	{ "0.jpg", "image/jpeg", "", 30, 20,  8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "4.jpg", "image/jpeg", "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "0.png", "image/png" , "", 30, 20,  8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "1.png", "image/png" , "", 30, 20,  8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "2.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "3.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "4.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "5.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "6.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "7.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+	{ "8.png", "image/png" , "", 32, 32, 32, 0, 999 }
+};
+
+static FLAC__bool debug_ = false;
+
+static FLAC__bool failed_(const char *msg)
+{
+	if(msg)
+		printf("FAILED, %s\n", msg);
+	else
+		printf("FAILED\n");
+
+	return false;
+}
+
+static FLAC__bool test_one_picture(const char *prefix, const PictureFile *pf, const PictureResolution * res, FLAC__bool fn_only)
+{
+	FLAC__StreamMetadata *obj;
+	const char *error;
+	char s[4096];
+	if(fn_only)
+		flac_snprintf(s, sizeof(s), "pictures/%s", pf->path);
+	else if (res == NULL)
+		flac_snprintf(s, sizeof(s), "%u|%s|%s||pictures/%s", (uint32_t)pf->type, pf->mime_type, pf->description, pf->path);
+	else
+		flac_snprintf(s, sizeof(s), "%u|%s|%s|%dx%dx%d/%d|pictures/%s", (uint32_t)pf->type, pf->mime_type, pf->description, res->width, res->height, res->depth, res->colors, pf->path);
+
+	printf("testing grabbag__picture_parse_specification(\"%s\")... ", s);
+
+	flac_snprintf(s, sizeof(s), "%s/%s", prefix, pf->path);
+	if((obj = grabbag__picture_from_specification(fn_only? FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER : pf->type, pf->mime_type, pf->description, res, s, &error)) == 0)
+		return failed_(error);
+	if(debug_) {
+		printf("\ntype=%u (%s)\nmime_type=%s\ndescription=%s\nwidth=%u\nheight=%u\ndepth=%u\ncolors=%u\ndata_length=%u\n",
+			obj->data.picture.type,
+			obj->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED?
+				FLAC__StreamMetadata_Picture_TypeString[obj->data.picture.type] : "UNDEFINED",
+			obj->data.picture.mime_type,
+			obj->data.picture.description,
+			obj->data.picture.width,
+			obj->data.picture.height,
+			obj->data.picture.depth,
+			obj->data.picture.colors,
+			obj->data.picture.data_length
+		);
+	}
+	if(obj->data.picture.type != (fn_only? FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER : pf->type))
+		return failed_("picture type mismatch");
+	if(strcmp(obj->data.picture.mime_type, pf->mime_type))
+		return failed_("picture MIME type mismatch");
+	if(strcmp((const char *)obj->data.picture.description, (const char *)pf->description))
+		return failed_("picture description mismatch");
+	if(obj->data.picture.width != pf->width)
+		return failed_("picture width mismatch");
+	if(obj->data.picture.height != pf->height)
+		return failed_("picture height mismatch");
+	if(obj->data.picture.depth != pf->depth)
+		return failed_("picture depth mismatch");
+	if(obj->data.picture.colors != pf->colors)
+		return failed_("picture colors mismatch");
+	printf("OK\n");
+	FLAC__metadata_object_delete(obj);
+	return true;
+}
+
+static FLAC__bool do_picture(const char *prefix)
+{
+	FLAC__StreamMetadata *obj;
+	PictureResolution res;
+	const char *error;
+	size_t i;
+
+	printf("\n+++ grabbag unit test: picture\n\n");
+
+	/* invalid spec: no filename */
+	printf("testing grabbag__picture_parse_specification(\"\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected, error: %s)\n", error);
+
+	/* invalid spec: no filename */
+	printf("testing grabbag__picture_parse_specification(\"||||\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("||||", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected: %s)\n", error);
+
+	/* invalid spec: no filename */
+	printf("testing grabbag__picture_parse_specification(\"|image/gif|||\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("|image/gif|||", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected: %s)\n", error);
+
+	/* invalid spec: bad resolution */
+	printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320|0.gif\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320|0.gif", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected: %s)\n", error);
+
+	/* invalid spec: bad resolution */
+	printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240|0.gif\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240|0.gif", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected: %s)\n", error);
+
+	/* invalid spec: no filename */
+	printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9|\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9|", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected: %s)\n", error);
+
+	/* invalid spec: #colors exceeds color depth */
+	printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9/2345|0.gif\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9/2345|0.gif", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected: %s)\n", error);
+
+	/* invalid spec: standard icon has to be 32x32 PNG */
+	printf("testing grabbag__picture_parse_specification(\"1|-->|desc|32x24x9|0.gif\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("1|-->|desc|32x24x9|0.gif", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected: %s)\n", error);
+
+	/* invalid spec: need resolution for linked URL */
+	printf("testing grabbag__picture_parse_specification(\"|-->|desc||http://blah.blah.blah/z.gif\")... ");
+	if(0 != (obj = grabbag__picture_parse_specification("|-->|desc||http://blah.blah.blah/z.gif", &error)))
+		return failed_("expected error, got object");
+	printf("OK (failed as expected: %s)\n", error);
+
+	printf("testing grabbag__picture_parse_specification(\"|-->|desc|320x240x9|http://blah.blah.blah/z.gif\")... ");
+	if(0 == (obj = grabbag__picture_parse_specification("|-->|desc|320x240x9|http://blah.blah.blah/z.gif", &error)))
+		return failed_(error);
+	printf("OK\n");
+	FLAC__metadata_object_delete(obj);
+
+	/* test automatic parsing of picture files from only the file name */
+	for(i = 0; i < sizeof(picturefiles)/sizeof(picturefiles[0]); i++)
+		if(!test_one_picture(prefix, picturefiles+i, NULL, /*fn_only=*/true))
+			return false;
+
+	/* test automatic parsing of picture files to get resolution/color info */
+	for(i = 0; i < sizeof(picturefiles)/sizeof(picturefiles[0]); i++)
+		if(!test_one_picture(prefix, picturefiles+i, NULL, /*fn_only=*/false))
+			return false;
+
+	res.width = picturefiles[0].width = 320;
+	res.height = picturefiles[0].height = 240;
+	res.depth = picturefiles[0].depth = 3;
+	res.colors = picturefiles[0].colors = 2;
+	if(!test_one_picture(prefix, picturefiles+0, &res, /*fn_only=*/false))
+		return false;
+
+	return true;
+}
+
+int main(int argc, char *argv[])
+{
+	const char *usage = "usage: test_pictures path_prefix\n";
+
+	if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+		puts(usage);
+		return 0;
+	}
+
+	if(argc != 2) {
+		fputs(usage, stderr);
+		return 255;
+	}
+
+	return do_picture(argv[1])? 0 : 1;
+}
diff --git a/src/test_grabbag/picture/test_picture.vcproj b/src/test_grabbag/picture/test_picture.vcproj
new file mode 100644
index 0000000..9ea0572
--- /dev/null
+++ b/src/test_grabbag/picture/test_picture.vcproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="test_picture"

+	ProjectGUID="{4cefbc8f-c215-11db-8314-0800200c9a66}"

+	RootNamespace="test_picture"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/test_grabbag/picture/test_picture.vcxproj b/src/test_grabbag/picture/test_picture.vcxproj
new file mode 100644
index 0000000..588c19e
--- /dev/null
+++ b/src/test_grabbag/picture/test_picture.vcxproj
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc8f-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>test_picture</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+    </ProjectReference>

+    <ProjectReference Include="..\..\share\grabbag\grabbag_static.vcxproj">

+      <Project>{4cefbc81-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_grabbag/picture/test_picture.vcxproj.filters b/src/test_grabbag/picture/test_picture.vcxproj.filters
new file mode 100644
index 0000000..5c9040b
--- /dev/null
+++ b/src/test_grabbag/picture/test_picture.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_libFLAC++/CMakeLists.txt b/src/test_libFLAC++/CMakeLists.txt
new file mode 100644
index 0000000..2fa7b1e
--- /dev/null
+++ b/src/test_libFLAC++/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_executable(test_libFLAC++
+    decoders.cpp
+    encoders.cpp
+    main.cpp
+    metadata.cpp
+    metadata_manip.cpp
+    metadata_object.cpp
+    $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+    $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(test_libFLAC++ FLAC++ test_libs_common grabbag)
diff --git a/src/test_libFLAC++/Makefile.am b/src/test_libFLAC++/Makefile.am
new file mode 100644
index 0000000..3183be7
--- /dev/null
+++ b/src/test_libFLAC++/Makefile.am
@@ -0,0 +1,54 @@
+#  test_libFLAC++ - Unit tester for libFLAC++
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	test_libFLAC++.vcproj \
+	test_libFLAC++.vcxproj \
+	test_libFLAC++.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+check_PROGRAMS = test_libFLAC++
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+test_libFLAC___LDADD = \
+	$(top_builddir)/src/share/grabbag/libgrabbag.la \
+	$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+	$(top_builddir)/src/test_libs_common/libtest_libs_common.la \
+	$(top_builddir)/src/libFLAC++/libFLAC++.la \
+	$(top_builddir)/src/libFLAC/libFLAC.la \
+	$(win_utf8_lib) \
+	@OGG_LIBS@ \
+	-lm
+
+test_libFLAC___SOURCES = \
+	decoders.cpp \
+	encoders.cpp \
+	main.cpp \
+	metadata.cpp \
+	metadata_manip.cpp \
+	metadata_object.cpp \
+	decoders.h \
+	encoders.h \
+	metadata.h
+
+CLEANFILES = test_libFLAC++.exe
diff --git a/src/test_libFLAC++/Makefile.lite b/src/test_libFLAC++/Makefile.lite
new file mode 100644
index 0000000..dd67788
--- /dev/null
+++ b/src/test_libFLAC++/Makefile.lite
@@ -0,0 +1,54 @@
+#  test_libFLAC++ - Unit tester for libFLAC++
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = test_libFLAC++
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libtest_libs_common.a $(libdir)/libFLAC++.a $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+ifeq ($(findstring Windows,$(OS)),Windows)
+    LIBS = -lgrabbag -lreplaygain_analysis -ltest_libs_common -lFLAC++ -lFLAC -lwin_utf8_io $(OGG_LIBS) -lm
+else
+    LIBS = -lgrabbag -lreplaygain_analysis -ltest_libs_common -lFLAC++ -lFLAC $(OGG_LIBS) -lm
+endif
+endif
+
+SRCS_CPP = \
+	decoders.cpp \
+	encoders.cpp \
+	main.cpp \
+	metadata.cpp \
+	metadata_manip.cpp \
+	metadata_object.cpp
+
+include $(topdir)/build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_libFLAC++/decoders.cpp b/src/test_libFLAC++/decoders.cpp
new file mode 100644
index 0000000..a363309
--- /dev/null
+++ b/src/test_libFLAC++/decoders.cpp
@@ -0,0 +1,1183 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "decoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h" // for ::FLAC__metadata_object_is_equal()
+#include "FLAC++/decoder.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+extern "C" {
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+}
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+typedef enum {
+	LAYER_STREAM = 0, /* FLAC__stream_decoder_init_stream() without seeking */
+	LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_stream() with seeking */
+	LAYER_FILE, /* FLAC__stream_decoder_init_FILE() */
+	LAYER_FILENAME /* FLAC__stream_decoder_init_file() */
+} Layer;
+
+static const char * const LayerString[] = {
+	"Stream",
+	"Seekable Stream",
+	"FILE*",
+	"Filename"
+};
+
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static ::FLAC__StreamMetadata *expected_metadata_sequence_[9];
+static uint32_t num_expected_;
+static FLAC__off_t flacfilesize_;
+
+static const char *flacfilename(bool is_ogg)
+{
+	return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static bool die_(const char *msg)
+{
+	printf("ERROR: %s\n", msg);
+	return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC::Decoder::Stream *decoder)
+{
+	FLAC::Decoder::Stream::State state = decoder->get_state();
+
+	if(msg)
+		printf("FAILED, %s", msg);
+	else
+		printf("FAILED");
+
+	printf(", state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
+
+	return false;
+}
+
+static void init_metadata_blocks_()
+{
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_()
+{
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static bool generate_file_(FLAC__bool is_ogg)
+{
+	printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":"");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &padding_;
+	expected_metadata_sequence_[num_expected_++] = &seektable_;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
+	expected_metadata_sequence_[num_expected_++] = &unknown_;
+	/* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
+
+	if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
+		return die_("creating the encoded file");
+
+	return true;
+}
+
+
+class DecoderCommon {
+public:
+	Layer layer_;
+	uint32_t current_metadata_number_;
+	bool ignore_errors_;
+	bool error_occurred_;
+
+	DecoderCommon(Layer layer): layer_(layer), current_metadata_number_(0), ignore_errors_(false), error_occurred_(false) { }
+	virtual ~DecoderCommon(void) { }
+	::FLAC__StreamDecoderWriteStatus common_write_callback_(const ::FLAC__Frame *frame);
+	void common_metadata_callback_(const ::FLAC__StreamMetadata *metadata);
+	void common_error_callback_(::FLAC__StreamDecoderErrorStatus status);
+};
+
+::FLAC__StreamDecoderWriteStatus DecoderCommon::common_write_callback_(const ::FLAC__Frame *frame)
+{
+	if(error_occurred_)
+		return ::FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+	if(
+		(frame->header.number_type == ::FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+		(frame->header.number_type == ::FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+	) {
+		printf("content... ");
+		fflush(stdout);
+	}
+
+	return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void DecoderCommon::common_metadata_callback_(const ::FLAC__StreamMetadata *metadata)
+{
+	if(error_occurred_)
+		return;
+
+	printf("%u... ", current_metadata_number_);
+	fflush(stdout);
+
+	if(current_metadata_number_ >= num_expected_) {
+		(void)die_("got more metadata blocks than expected");
+		error_occurred_ = true;
+	}
+	else {
+		if(!::FLAC__metadata_object_is_equal(expected_metadata_sequence_[current_metadata_number_], metadata)) {
+			(void)die_("metadata block mismatch");
+			error_occurred_ = true;
+		}
+	}
+	current_metadata_number_++;
+}
+
+void DecoderCommon::common_error_callback_(::FLAC__StreamDecoderErrorStatus status)
+{
+	if(!ignore_errors_) {
+		printf("ERROR: got error callback: err = %u (%s)\n", (uint32_t)status, ::FLAC__StreamDecoderErrorStatusString[status]);
+		error_occurred_ = true;
+	}
+}
+
+class StreamDecoder : public FLAC::Decoder::Stream, public DecoderCommon {
+public:
+	FILE *file_;
+
+	StreamDecoder(Layer layer): FLAC::Decoder::Stream(), DecoderCommon(layer), file_(0) { }
+	~StreamDecoder() { }
+
+	// from FLAC::Decoder::Stream
+	::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
+	::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+	::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+	::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length);
+	bool eof_callback();
+	::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+	void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+	void error_callback(::FLAC__StreamDecoderErrorStatus status);
+
+	bool test_respond(bool is_ogg);
+private:
+	StreamDecoder(const StreamDecoder&);
+	StreamDecoder&operator=(const StreamDecoder&);
+};
+
+::FLAC__StreamDecoderReadStatus StreamDecoder::read_callback(FLAC__byte buffer[], size_t *bytes)
+{
+	const size_t requested_bytes = *bytes;
+
+	if(error_occurred_)
+		return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+	if(feof(file_)) {
+		*bytes = 0;
+		return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+	}
+	else if(requested_bytes > 0) {
+		*bytes = ::fread(buffer, 1, requested_bytes, file_);
+		if(*bytes == 0) {
+			if(feof(file_))
+				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__StreamDecoderSeekStatus StreamDecoder::seek_callback(FLAC__uint64 absolute_byte_offset)
+{
+	if(layer_ == LAYER_STREAM)
+		return ::FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+
+	if(error_occurred_)
+		return ::FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+
+	if(fseeko(file_, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) {
+		error_occurred_ = true;
+		return ::FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+	}
+
+	return ::FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+::FLAC__StreamDecoderTellStatus StreamDecoder::tell_callback(FLAC__uint64 *absolute_byte_offset)
+{
+	if(layer_ == LAYER_STREAM)
+		return ::FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+
+	if(error_occurred_)
+		return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+
+	FLAC__off_t offset = ftello(file_);
+	*absolute_byte_offset = (FLAC__uint64)offset;
+
+	if(offset < 0) {
+		error_occurred_ = true;
+		return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+	}
+
+	return ::FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+::FLAC__StreamDecoderLengthStatus StreamDecoder::length_callback(FLAC__uint64 *stream_length)
+{
+	if(layer_ == LAYER_STREAM)
+		return ::FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+
+	if(error_occurred_)
+		return ::FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+	*stream_length = (FLAC__uint64)flacfilesize_;
+	return ::FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+bool StreamDecoder::eof_callback()
+{
+	if(layer_ == LAYER_STREAM)
+		return false;
+
+	if(error_occurred_)
+		return true;
+
+	return (bool)feof(file_);
+}
+
+::FLAC__StreamDecoderWriteStatus StreamDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+	(void)buffer;
+
+	return common_write_callback_(frame);
+}
+
+void StreamDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+	common_metadata_callback_(metadata);
+}
+
+void StreamDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+	common_error_callback_(status);
+}
+
+bool StreamDecoder::test_respond(bool is_ogg)
+{
+	::FLAC__StreamDecoderInitStatus init_status;
+
+	if(!set_md5_checking(true)) {
+		printf("FAILED at set_md5_checking(), returned false\n");
+		return false;
+	}
+
+	printf("testing init%s()... ", is_ogg? "_ogg":"");
+	init_status = is_ogg? init_ogg() : init();
+	if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
+		return die_s_(0, this);
+	printf("OK\n");
+
+	current_metadata_number_ = 0;
+
+	if(fseeko(file_, 0, SEEK_SET) < 0) {
+		printf("FAILED rewinding input, errno = %d\n", errno);
+		return false;
+	}
+
+	printf("testing process_until_end_of_stream()... ");
+	if(!process_until_end_of_stream()) {
+		State state = get_state();
+		printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing finish()... ");
+	if(!finish()) {
+		State state = get_state();
+		printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
+		return false;
+	}
+	printf("OK\n");
+
+	return true;
+}
+
+class FileDecoder : public FLAC::Decoder::File, public DecoderCommon {
+public:
+	FileDecoder(Layer layer): FLAC::Decoder::File(), DecoderCommon(layer) { }
+	~FileDecoder() { }
+
+	// from FLAC::Decoder::Stream
+	::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+	void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+	void error_callback(::FLAC__StreamDecoderErrorStatus status);
+
+	bool test_respond(bool is_ogg);
+};
+
+::FLAC__StreamDecoderWriteStatus FileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+	(void)buffer;
+	return common_write_callback_(frame);
+}
+
+void FileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+	common_metadata_callback_(metadata);
+}
+
+void FileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+	common_error_callback_(status);
+}
+
+bool FileDecoder::test_respond(bool is_ogg)
+{
+	::FLAC__StreamDecoderInitStatus init_status;
+
+	if(!set_md5_checking(true)) {
+		printf("FAILED at set_md5_checking(), returned false\n");
+		return false;
+	}
+
+	switch(layer_) {
+		case LAYER_FILE:
+			{
+				printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+				FILE *file = ::flac_fopen(flacfilename(is_ogg), "rb");
+				if(0 == file) {
+					printf("ERROR (%s)\n", strerror(errno));
+					return false;
+				}
+				printf("OK\n");
+
+				printf("testing init%s()... ", is_ogg? "_ogg":"");
+				init_status = is_ogg? init_ogg(file) : init(file);
+			}
+			break;
+		case LAYER_FILENAME:
+			printf("testing init%s()... ", is_ogg? "_ogg":"");
+			init_status = is_ogg? init_ogg(flacfilename(is_ogg)) : init(flacfilename(is_ogg));
+			break;
+		default:
+			die_("internal error 001");
+			return false;
+	}
+	if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
+		return die_s_(0, this);
+	printf("OK\n");
+
+	current_metadata_number_ = 0;
+
+	printf("testing process_until_end_of_stream()... ");
+	if(!process_until_end_of_stream()) {
+		State state = get_state();
+		printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing finish()... ");
+	if(!finish()) {
+		State state = get_state();
+		printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
+		return false;
+	}
+	printf("OK\n");
+
+	return true;
+}
+
+
+static FLAC::Decoder::Stream *new_by_layer(Layer layer)
+{
+	if(layer < LAYER_FILE)
+		return new StreamDecoder(layer);
+	else
+		return new FileDecoder(layer);
+}
+
+static bool test_stream_decoder(Layer layer, bool is_ogg)
+{
+	FLAC::Decoder::Stream *decoder;
+	::FLAC__StreamDecoderInitStatus init_status;
+	bool expect;
+
+	printf("\n+++ libFLAC++ unit test: FLAC::Decoder::%s (layer: %s, format: %s)\n\n", layer<LAYER_FILE? "Stream":"File", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC");
+
+	//
+	// test new -> delete
+	//
+	printf("allocating decoder instance... ");
+	decoder = new_by_layer(layer);
+	if(0 == decoder) {
+		printf("FAILED, new returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing is_valid()... ");
+	if(!decoder->is_valid()) {
+		printf("FAILED, returned false\n");
+		delete decoder;
+		return false;
+	}
+	printf("OK\n");
+
+	printf("freeing decoder instance... ");
+	delete decoder;
+	printf("OK\n");
+
+	//
+	// test new -> init -> delete
+	//
+	printf("allocating decoder instance... ");
+	decoder = new_by_layer(layer);
+	if(0 == decoder) {
+		printf("FAILED, new returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing is_valid()... ");
+	if(!decoder->is_valid()) {
+		printf("FAILED, returned false\n");
+		delete decoder;
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing init%s()... ", is_ogg? "_ogg":"");
+	switch(layer) {
+		case LAYER_STREAM:
+		case LAYER_SEEKABLE_STREAM:
+			dynamic_cast<StreamDecoder*>(decoder)->file_ = stdin;
+			init_status = is_ogg? decoder->init_ogg() : decoder->init();
+			break;
+		case LAYER_FILE:
+			init_status = is_ogg?
+				dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(stdin) :
+				dynamic_cast<FLAC::Decoder::File*>(decoder)->init(stdin);
+			break;
+		case LAYER_FILENAME:
+			init_status = is_ogg?
+				dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(flacfilename(is_ogg)) :
+				dynamic_cast<FLAC::Decoder::File*>(decoder)->init(flacfilename(is_ogg));
+			break;
+		default:
+			die_("internal error 006");
+			delete decoder;
+			return false;
+	}
+	if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
+		return die_s_(0, decoder);
+	printf("OK\n");
+
+	printf("freeing decoder instance... ");
+	delete decoder;
+	printf("OK\n");
+
+	//
+	// test normal usage
+	//
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+	printf("allocating decoder instance... ");
+	decoder = new_by_layer(layer);
+	if(0 == decoder) {
+		printf("FAILED, new returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing is_valid()... ");
+	if(!decoder->is_valid()) {
+		printf("FAILED, returned false\n");
+		delete decoder;
+		return false;
+	}
+	printf("OK\n");
+
+	if(is_ogg) {
+		printf("testing set_ogg_serial_number()... ");
+		if(!decoder->set_ogg_serial_number(file_utils__ogg_serial_number))
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+	}
+
+	if(!decoder->set_md5_checking(true)) {
+		printf("FAILED at set_md5_checking(), returned false\n");
+		return false;
+	}
+
+	switch(layer) {
+		case LAYER_STREAM:
+		case LAYER_SEEKABLE_STREAM:
+			printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+			dynamic_cast<StreamDecoder*>(decoder)->file_ = ::flac_fopen(flacfilename(is_ogg), "rb");
+			if(0 == dynamic_cast<StreamDecoder*>(decoder)->file_) {
+				printf("ERROR (%s)\n", strerror(errno));
+				return false;
+			}
+			printf("OK\n");
+
+			printf("testing init%s()... ", is_ogg? "_ogg":"");
+			init_status = is_ogg? decoder->init_ogg() : decoder->init();
+			break;
+		case LAYER_FILE:
+			{
+				printf("opening FLAC file... ");
+				FILE *file = ::flac_fopen(flacfilename(is_ogg), "rb");
+				if(0 == file) {
+					printf("ERROR (%s)\n", strerror(errno));
+					return false;
+				}
+				printf("OK\n");
+
+				printf("testing init%s()... ", is_ogg? "_ogg":"");
+				init_status = is_ogg?
+					dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(file) :
+					dynamic_cast<FLAC::Decoder::File*>(decoder)->init(file);
+			}
+			break;
+		case LAYER_FILENAME:
+			printf("testing init%s()... ", is_ogg? "_ogg":"");
+			init_status = is_ogg?
+				dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(flacfilename(is_ogg)) :
+				dynamic_cast<FLAC::Decoder::File*>(decoder)->init(flacfilename(is_ogg));
+			break;
+		default:
+			die_("internal error 009");
+			return false;
+	}
+	if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
+		return die_s_(0, decoder);
+	printf("OK\n");
+
+	printf("testing get_state()... ");
+	FLAC::Decoder::Stream::State state = decoder->get_state();
+	printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
+
+	dynamic_cast<DecoderCommon*>(decoder)->current_metadata_number_ = 0;
+	dynamic_cast<DecoderCommon*>(decoder)->ignore_errors_ = false;
+	dynamic_cast<DecoderCommon*>(decoder)->error_occurred_ = false;
+
+	printf("testing get_md5_checking()... ");
+	if(!decoder->get_md5_checking()) {
+		printf("FAILED, returned false, expected true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing process_until_end_of_metadata()... ");
+	if(!decoder->process_until_end_of_metadata())
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing process_single()... ");
+	if(!decoder->process_single())
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing skip_single_frame()... ");
+	if(!decoder->skip_single_frame())
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	if(layer < LAYER_FILE) {
+		printf("testing flush()... ");
+		if(!decoder->flush())
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+
+		dynamic_cast<DecoderCommon*>(decoder)->ignore_errors_ = true;
+		printf("testing process_single()... ");
+		if(!decoder->process_single())
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+		dynamic_cast<DecoderCommon*>(decoder)->ignore_errors_ = false;
+	}
+
+	expect = (layer != LAYER_STREAM);
+	printf("testing seek_absolute()... ");
+	if(decoder->seek_absolute(0) != expect)
+		return die_s_(expect? "returned false" : "returned true", decoder);
+	printf("OK\n");
+
+	printf("testing process_until_end_of_stream()... ");
+	if(!decoder->process_until_end_of_stream())
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	expect = (layer != LAYER_STREAM);
+	printf("testing seek_absolute()... ");
+	if(decoder->seek_absolute(0) != expect)
+		return die_s_(expect? "returned false" : "returned true", decoder);
+	printf("OK\n");
+
+	printf("testing get_channels()... ");
+	{
+		uint32_t channels = decoder->get_channels();
+		if(channels != streaminfo_.data.stream_info.channels) {
+			printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels);
+			return false;
+		}
+	}
+	printf("OK\n");
+
+	printf("testing get_bits_per_sample()... ");
+	{
+		uint32_t bits_per_sample = decoder->get_bits_per_sample();
+		if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) {
+			printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample);
+			return false;
+		}
+	}
+	printf("OK\n");
+
+	printf("testing get_sample_rate()... ");
+	{
+		uint32_t sample_rate = decoder->get_sample_rate();
+		if(sample_rate != streaminfo_.data.stream_info.sample_rate) {
+			printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate);
+			return false;
+		}
+	}
+	printf("OK\n");
+
+	printf("testing get_blocksize()... ");
+	{
+		uint32_t blocksize = decoder->get_blocksize();
+		/* value could be anything since we're at the last block, so accept any reasonable answer */
+		printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED");
+		if(blocksize == 0)
+			return false;
+	}
+
+	printf("testing get_channel_assignment()... ");
+	{
+		::FLAC__ChannelAssignment ca = decoder->get_channel_assignment();
+		printf("returned %u (%s)... OK\n", (uint32_t)ca, ::FLAC__ChannelAssignmentString[ca]);
+	}
+
+	if(layer < LAYER_FILE) {
+		printf("testing reset()... ");
+		if(!decoder->reset())
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+
+		if(layer == LAYER_STREAM) {
+			/* after a reset() we have to rewind the input ourselves */
+			printf("rewinding input... ");
+			if(fseeko(dynamic_cast<StreamDecoder*>(decoder)->file_, 0, SEEK_SET) < 0) {
+				printf("FAILED, errno = %d\n", errno);
+				return false;
+			}
+			printf("OK\n");
+		}
+
+		dynamic_cast<DecoderCommon*>(decoder)->current_metadata_number_ = 0;
+
+		printf("testing process_until_end_of_stream()... ");
+		if(!decoder->process_until_end_of_stream())
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+	}
+
+	printf("testing finish()... ");
+	if(!decoder->finish()) {
+		state = decoder->get_state();
+		printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
+		return false;
+	}
+	printf("OK\n");
+
+	/*
+	 * respond all
+	 */
+
+	printf("testing set_metadata_respond_all()... ");
+	if(!decoder->set_metadata_respond_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application1_;
+		expected_metadata_sequence_[num_expected_++] = &application2_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application1_;
+		expected_metadata_sequence_[num_expected_++] = &application2_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * ignore all
+	 */
+
+	printf("testing set_metadata_ignore_all()... ");
+	if(!decoder->set_metadata_ignore_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * respond all, ignore VORBIS_COMMENT
+	 */
+
+	printf("testing set_metadata_respond_all()... ");
+	if(!decoder->set_metadata_respond_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_ignore(VORBIS_COMMENT)... ");
+	if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+	expected_metadata_sequence_[num_expected_++] = &padding_;
+	expected_metadata_sequence_[num_expected_++] = &seektable_;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
+	expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * respond all, ignore APPLICATION
+	 */
+
+	printf("testing set_metadata_respond_all()... ");
+	if(!decoder->set_metadata_respond_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_ignore(APPLICATION)... ");
+	if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_APPLICATION)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * respond all, ignore APPLICATION id of app#1
+	 */
+
+	printf("testing set_metadata_respond_all()... ");
+	if(!decoder->set_metadata_respond_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_ignore_application(of app block #1)... ");
+	if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application2_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application2_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * respond all, ignore APPLICATION id of app#1 & app#2
+	 */
+
+	printf("testing set_metadata_respond_all()... ");
+	if(!decoder->set_metadata_respond_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_ignore_application(of app block #1)... ");
+	if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_ignore_application(of app block #2)... ");
+	if(!decoder->set_metadata_ignore_application(application2_.data.application.id)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * ignore all, respond VORBIS_COMMENT
+	 */
+
+	printf("testing set_metadata_ignore_all()... ");
+	if(!decoder->set_metadata_ignore_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_respond(VORBIS_COMMENT)... ");
+	if(!decoder->set_metadata_respond(FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * ignore all, respond APPLICATION
+	 */
+
+	printf("testing set_metadata_ignore_all()... ");
+	if(!decoder->set_metadata_ignore_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_respond(APPLICATION)... ");
+	if(!decoder->set_metadata_respond(FLAC__METADATA_TYPE_APPLICATION)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * ignore all, respond APPLICATION id of app#1
+	 */
+
+	printf("testing set_metadata_ignore_all()... ");
+	if(!decoder->set_metadata_ignore_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_respond_application(of app block #1)... ");
+	if(!decoder->set_metadata_respond_application(application1_.data.application.id)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * ignore all, respond APPLICATION id of app#1 & app#2
+	 */
+
+	printf("testing set_metadata_ignore_all()... ");
+	if(!decoder->set_metadata_ignore_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_respond_application(of app block #1)... ");
+	if(!decoder->set_metadata_respond_application(application1_.data.application.id)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_respond_application(of app block #2)... ");
+	if(!decoder->set_metadata_respond_application(application2_.data.application.id)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+	 */
+
+	printf("testing set_metadata_respond_all()... ");
+	if(!decoder->set_metadata_respond_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_ignore(APPLICATION)... ");
+	if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_APPLICATION)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_respond_application(of app block #1)... ");
+	if(!decoder->set_metadata_respond_application(application1_.data.application.id)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application1_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application1_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	/*
+	 * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+	 */
+
+	printf("testing set_metadata_ignore_all()... ");
+	if(!decoder->set_metadata_ignore_all()) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_respond(APPLICATION)... ");
+	if(!decoder->set_metadata_respond(FLAC__METADATA_TYPE_APPLICATION)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing set_metadata_ignore_application(of app block #1)... ");
+	if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+
+	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+		return false;
+
+	if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
+		::fclose(dynamic_cast<StreamDecoder*>(decoder)->file_);
+
+	printf("freeing decoder instance... ");
+	delete decoder;
+	printf("OK\n");
+
+	printf("\nPASSED!\n");
+
+	return true;
+}
+
+bool test_decoders()
+{
+	FLAC__bool is_ogg = false;
+
+	while(1) {
+		init_metadata_blocks_();
+
+		if(!generate_file_(is_ogg))
+			return false;
+
+		if(!test_stream_decoder(LAYER_STREAM, is_ogg))
+			return false;
+
+		if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg))
+			return false;
+
+		if(!test_stream_decoder(LAYER_FILE, is_ogg))
+			return false;
+
+		if(!test_stream_decoder(LAYER_FILENAME, is_ogg))
+			return false;
+
+		(void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+		free_metadata_blocks_();
+
+		if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+			break;
+		is_ogg = true;
+	}
+
+	return true;
+}
diff --git a/src/test_libFLAC++/decoders.h b/src/test_libFLAC++/decoders.h
new file mode 100644
index 0000000..39e1e83
--- /dev/null
+++ b/src/test_libFLAC++/decoders.h
@@ -0,0 +1,25 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLACPP_DECODERS_H
+#define FLAC__TEST_LIBFLACPP_DECODERS_H
+
+bool test_decoders();
+
+#endif
diff --git a/src/test_libFLAC++/encoders.cpp b/src/test_libFLAC++/encoders.cpp
new file mode 100644
index 0000000..306e323
--- /dev/null
+++ b/src/test_libFLAC++/encoders.cpp
@@ -0,0 +1,564 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "encoders.h"
+#include "FLAC/assert.h"
+#include "FLAC++/encoder.h"
+#include "share/grabbag.h"
+extern "C" {
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+}
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+typedef enum {
+	LAYER_STREAM = 0, /* FLAC__stream_encoder_init_stream() without seeking */
+	LAYER_SEEKABLE_STREAM, /* FLAC__stream_encoder_init_stream() with seeking */
+	LAYER_FILE, /* FLAC__stream_encoder_init_FILE() */
+	LAYER_FILENAME /* FLAC__stream_encoder_init_file() */
+} Layer;
+
+static const char * const LayerString[] = {
+	"Stream",
+	"Seekable Stream",
+	"FILE*",
+	"Filename"
+};
+
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static ::FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ };
+static const uint32_t num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
+
+static const char *flacfilename(bool is_ogg)
+{
+	return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static bool die_(const char *msg)
+{
+	printf("ERROR: %s\n", msg);
+	return false;
+}
+
+static bool die_s_(const char *msg, const FLAC::Encoder::Stream *encoder)
+{
+	FLAC::Encoder::Stream::State state = encoder->get_state();
+
+	if(msg)
+		printf("FAILED, %s", msg);
+	else
+		printf("FAILED");
+
+	printf(", state = %u (%s)\n", (uint32_t)((::FLAC__StreamEncoderState)state), state.as_cstring());
+	if(state == ::FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+		FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state();
+		printf("      verify decoder state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+	}
+
+	return false;
+}
+
+static void init_metadata_blocks_()
+{
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_()
+{
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+class StreamEncoder : public FLAC::Encoder::Stream {
+public:
+	Layer layer_;
+	FILE *file_;
+
+	StreamEncoder(Layer layer): FLAC::Encoder::Stream(), layer_(layer), file_(0) { }
+	~StreamEncoder() { }
+
+	// from FLAC::Encoder::Stream
+	::FLAC__StreamEncoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
+	::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame);
+	::FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+	::FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+	void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+private:
+	StreamEncoder(const StreamEncoder&);
+	StreamEncoder&operator=(const StreamEncoder&);
+};
+
+::FLAC__StreamEncoderReadStatus StreamEncoder::read_callback(FLAC__byte buffer[], size_t *bytes)
+{
+	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;
+}
+
+::FLAC__StreamEncoderWriteStatus StreamEncoder::write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame)
+{
+	(void)samples, (void)current_frame;
+
+	if(fwrite(buffer, 1, bytes, file_) != bytes)
+		return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+	else
+		return ::FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+::FLAC__StreamEncoderSeekStatus StreamEncoder::seek_callback(FLAC__uint64 absolute_byte_offset)
+{
+	if(layer_==LAYER_STREAM)
+		return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+	else if(fseeko(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 StreamEncoder::tell_callback(FLAC__uint64 *absolute_byte_offset)
+{
+	FLAC__off_t pos;
+	if(layer_==LAYER_STREAM)
+		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;
+	}
+}
+
+void StreamEncoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+	(void)metadata;
+}
+
+class FileEncoder : public FLAC::Encoder::File {
+public:
+	Layer layer_;
+
+	FileEncoder(Layer layer): FLAC::Encoder::File(), layer_(layer) { }
+	~FileEncoder() { }
+
+	// from FLAC::Encoder::File
+	void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate);
+};
+
+void FileEncoder::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate)
+{
+	(void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate;
+}
+
+static FLAC::Encoder::Stream *new_by_layer(Layer layer)
+{
+	if(layer < LAYER_FILE)
+		return new StreamEncoder(layer);
+	else
+		return new FileEncoder(layer);
+}
+
+static bool test_stream_encoder(Layer layer, bool is_ogg)
+{
+	FLAC::Encoder::Stream *encoder;
+	::FLAC__StreamEncoderInitStatus init_status;
+	FILE *file = 0;
+	FLAC__int32 samples[1024];
+	FLAC__int32 *samples_array[1] = { samples };
+	uint32_t i;
+
+	printf("\n+++ libFLAC++ unit test: FLAC::Encoder::%s (layer: %s, format: %s)\n\n", layer<LAYER_FILE? "Stream":"File", LayerString[layer], is_ogg? "Ogg FLAC":"FLAC");
+
+	printf("allocating encoder instance... ");
+	encoder = new_by_layer(layer);
+	if(0 == encoder) {
+		printf("FAILED, new returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing is_valid()... ");
+	if(!encoder->is_valid()) {
+		printf("FAILED, returned false\n");
+		delete encoder;
+		return false;
+	}
+	printf("OK\n");
+
+	if(is_ogg) {
+		printf("testing set_ogg_serial_number()... ");
+		if(!encoder->set_ogg_serial_number(file_utils__ogg_serial_number))
+			return die_s_("returned false", encoder);
+		printf("OK\n");
+	}
+
+	printf("testing set_verify()... ");
+	if(!encoder->set_verify(true))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_streamable_subset()... ");
+	if(!encoder->set_streamable_subset(true))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_channels()... ");
+	if(!encoder->set_channels(streaminfo_.data.stream_info.channels))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_bits_per_sample()... ");
+	if(!encoder->set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_sample_rate()... ");
+	if(!encoder->set_sample_rate(streaminfo_.data.stream_info.sample_rate))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_compression_level()... ");
+	if(!encoder->set_compression_level((uint32_t)(-1)))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_blocksize()... ");
+	if(!encoder->set_blocksize(streaminfo_.data.stream_info.min_blocksize))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_do_mid_side_stereo()... ");
+	if(!encoder->set_do_mid_side_stereo(false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_loose_mid_side_stereo()... ");
+	if(!encoder->set_loose_mid_side_stereo(false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_max_lpc_order()... ");
+	if(!encoder->set_max_lpc_order(0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_qlp_coeff_precision()... ");
+	if(!encoder->set_qlp_coeff_precision(0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_do_qlp_coeff_prec_search()... ");
+	if(!encoder->set_do_qlp_coeff_prec_search(false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_do_escape_coding()... ");
+	if(!encoder->set_do_escape_coding(false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_do_exhaustive_model_search()... ");
+	if(!encoder->set_do_exhaustive_model_search(false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_min_residual_partition_order()... ");
+	if(!encoder->set_min_residual_partition_order(0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_max_residual_partition_order()... ");
+	if(!encoder->set_max_residual_partition_order(0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_rice_parameter_search_dist()... ");
+	if(!encoder->set_rice_parameter_search_dist(0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_total_samples_estimate()... ");
+	if(!encoder->set_total_samples_estimate(streaminfo_.data.stream_info.total_samples))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing set_metadata()... ");
+	if(!encoder->set_metadata(metadata_sequence_, num_metadata_))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	if(layer < LAYER_FILENAME) {
+		printf("opening file for FLAC output... ");
+		file = ::flac_fopen(flacfilename(is_ogg), "w+b");
+		if(0 == file) {
+			printf("ERROR (%s)\n", strerror(errno));
+			return false;
+		}
+		printf("OK\n");
+		if(layer < LAYER_FILE)
+			dynamic_cast<StreamEncoder*>(encoder)->file_ = file;
+	}
+
+	switch(layer) {
+		case LAYER_STREAM:
+		case LAYER_SEEKABLE_STREAM:
+			printf("testing init%s()... ", is_ogg? "_ogg":"");
+			init_status = is_ogg? encoder->init_ogg() : encoder->init();
+			break;
+		case LAYER_FILE:
+			printf("testing init%s()... ", is_ogg? "_ogg":"");
+			init_status = is_ogg?
+				dynamic_cast<FLAC::Encoder::File*>(encoder)->init_ogg(file) :
+				dynamic_cast<FLAC::Encoder::File*>(encoder)->init(file);
+			break;
+		case LAYER_FILENAME:
+			printf("testing init%s()... ", is_ogg? "_ogg":"");
+			init_status = is_ogg?
+				dynamic_cast<FLAC::Encoder::File*>(encoder)->init_ogg(flacfilename(is_ogg)) :
+				dynamic_cast<FLAC::Encoder::File*>(encoder)->init(flacfilename(is_ogg));
+			break;
+		default:
+			die_("internal error 001");
+			return false;
+	}
+	if(init_status != ::FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+		return die_s_(0, encoder);
+	printf("OK\n");
+
+	printf("testing get_state()... ");
+	FLAC::Encoder::Stream::State state = encoder->get_state();
+	printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamEncoderState)state), state.as_cstring());
+
+	printf("testing get_verify_decoder_state()... ");
+	FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state();
+	printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+
+	{
+		FLAC__uint64 absolute_sample;
+		uint32_t frame_number;
+		uint32_t channel;
+		uint32_t sample;
+		FLAC__int32 expected;
+		FLAC__int32 got;
+
+		printf("testing get_verify_decoder_error_stats()... ");
+		encoder->get_verify_decoder_error_stats(&absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+		printf("OK\n");
+	}
+
+	printf("testing get_verify()... ");
+	if(encoder->get_verify() != true) {
+		printf("FAILED, expected true, got false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_streamable_subset()... ");
+	if(encoder->get_streamable_subset() != true) {
+		printf("FAILED, expected true, got false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_do_mid_side_stereo()... ");
+	if(encoder->get_do_mid_side_stereo() != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_loose_mid_side_stereo()... ");
+	if(encoder->get_loose_mid_side_stereo() != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_channels()... ");
+	if(encoder->get_channels() != streaminfo_.data.stream_info.channels) {
+		printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, encoder->get_channels());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_bits_per_sample()... ");
+	if(encoder->get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample) {
+		printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, encoder->get_bits_per_sample());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_sample_rate()... ");
+	if(encoder->get_sample_rate() != streaminfo_.data.stream_info.sample_rate) {
+		printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, encoder->get_sample_rate());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_blocksize()... ");
+	if(encoder->get_blocksize() != streaminfo_.data.stream_info.min_blocksize) {
+		printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, encoder->get_blocksize());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_max_lpc_order()... ");
+	if(encoder->get_max_lpc_order() != 0) {
+		printf("FAILED, expected %d, got %u\n", 0, encoder->get_max_lpc_order());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_qlp_coeff_precision()... ");
+	(void)encoder->get_qlp_coeff_precision();
+	/* we asked the encoder to auto select this so we accept anything */
+	printf("OK\n");
+
+	printf("testing get_do_qlp_coeff_prec_search()... ");
+	if(encoder->get_do_qlp_coeff_prec_search() != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_do_escape_coding()... ");
+	if(encoder->get_do_escape_coding() != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_do_exhaustive_model_search()... ");
+	if(encoder->get_do_exhaustive_model_search() != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_min_residual_partition_order()... ");
+	if(encoder->get_min_residual_partition_order() != 0) {
+		printf("FAILED, expected %d, got %u\n", 0, encoder->get_min_residual_partition_order());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_max_residual_partition_order()... ");
+	if(encoder->get_max_residual_partition_order() != 0) {
+		printf("FAILED, expected %d, got %u\n", 0, encoder->get_max_residual_partition_order());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_rice_parameter_search_dist()... ");
+	if(encoder->get_rice_parameter_search_dist() != 0) {
+		printf("FAILED, expected %d, got %u\n", 0, encoder->get_rice_parameter_search_dist());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing get_total_samples_estimate()... ");
+	if(encoder->get_total_samples_estimate() != streaminfo_.data.stream_info.total_samples) {
+		printf("FAILED, expected %" PRIu64 ", got %" PRIu64 "\n", streaminfo_.data.stream_info.total_samples, encoder->get_total_samples_estimate());
+		return false;
+	}
+	printf("OK\n");
+
+	/* init the dummy sample buffer */
+	for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+		samples[i] = i & 7;
+
+	printf("testing process()... ");
+	if(!encoder->process(samples_array, sizeof(samples) / sizeof(FLAC__int32)))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing process_interleaved()... ");
+	if(!encoder->process_interleaved(samples, sizeof(samples) / sizeof(FLAC__int32)))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing finish()... ");
+	if(!encoder->finish()) {
+		state = encoder->get_state();
+		printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamEncoderState)state), state.as_cstring());
+		return false;
+	}
+	printf("OK\n");
+
+	if(layer < LAYER_FILE)
+		::fclose(dynamic_cast<StreamEncoder*>(encoder)->file_);
+
+	printf("freeing encoder instance... ");
+	delete encoder;
+	printf("OK\n");
+
+	printf("\nPASSED!\n");
+
+	return true;
+}
+
+bool test_encoders()
+{
+	FLAC__bool is_ogg = false;
+
+	while(1) {
+		init_metadata_blocks_();
+
+		if(!test_stream_encoder(LAYER_STREAM, is_ogg))
+			return false;
+
+		if(!test_stream_encoder(LAYER_SEEKABLE_STREAM, is_ogg))
+			return false;
+
+		if(!test_stream_encoder(LAYER_FILE, is_ogg))
+			return false;
+
+		if(!test_stream_encoder(LAYER_FILENAME, is_ogg))
+			return false;
+
+		(void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+		free_metadata_blocks_();
+
+		if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+			break;
+		is_ogg = true;
+	}
+
+	return true;
+}
diff --git a/src/test_libFLAC++/encoders.h b/src/test_libFLAC++/encoders.h
new file mode 100644
index 0000000..a611cae
--- /dev/null
+++ b/src/test_libFLAC++/encoders.h
@@ -0,0 +1,25 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLACPP_ENCODERS_H
+#define FLAC__TEST_LIBFLACPP_ENCODERS_H
+
+bool test_encoders();
+
+#endif
diff --git a/src/test_libFLAC++/main.cpp b/src/test_libFLAC++/main.cpp
new file mode 100644
index 0000000..f111fc7
--- /dev/null
+++ b/src/test_libFLAC++/main.cpp
@@ -0,0 +1,42 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "decoders.h"
+#include "encoders.h"
+#include "metadata.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argc, (void)argv;
+
+	if(!test_encoders())
+		return 1;
+
+	if(!test_decoders())
+		return 1;
+
+	if(!test_metadata())
+		return 1;
+
+	return 0;
+}
diff --git a/src/test_libFLAC++/metadata.cpp b/src/test_libFLAC++/metadata.cpp
new file mode 100644
index 0000000..19971fc
--- /dev/null
+++ b/src/test_libFLAC++/metadata.cpp
@@ -0,0 +1,41 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "metadata.h"
+#include <stdio.h>
+
+extern bool test_metadata_object();
+extern bool test_metadata_file_manipulation();
+
+bool test_metadata()
+{
+	if(!test_metadata_object())
+		return false;
+
+	if(!test_metadata_file_manipulation())
+		return false;
+
+	printf("\nPASSED!\n");
+
+	return true;
+}
diff --git a/src/test_libFLAC++/metadata.h b/src/test_libFLAC++/metadata.h
new file mode 100644
index 0000000..e66e578
--- /dev/null
+++ b/src/test_libFLAC++/metadata.h
@@ -0,0 +1,25 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLACPP_METADATA_H
+#define FLAC__TEST_LIBFLACPP_METADATA_H
+
+bool test_metadata();
+
+#endif
diff --git a/src/test_libFLAC++/metadata_manip.cpp b/src/test_libFLAC++/metadata_manip.cpp
new file mode 100644
index 0000000..f9380d9
--- /dev/null
+++ b/src/test_libFLAC++/metadata_manip.cpp
@@ -0,0 +1,2235 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy()/memset() */
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#ifdef _MSC_VER
+#include <sys/utime.h>
+#endif
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#include "FLAC/assert.h"
+#include "FLAC++/decoder.h"
+#include "FLAC++/metadata.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "share/macros.h"
+#include "share/safe_str.h"
+extern "C" {
+#include "test_libs_common/file_utils_flac.h"
+}
+
+/******************************************************************************
+	The general strategy of these tests (for interface levels 1 and 2) is
+	to create a dummy FLAC file with a known set of initial metadata
+	blocks, then keep a mirror locally of what we expect the metadata to be
+	after each operation.  Then testing becomes a simple matter of running
+	a FLAC::Decoder::File over the dummy file after each operation, comparing
+	the decoded metadata to what's in our local copy.  If there are any
+	differences in the metadata, or the actual audio data is corrupted, we
+	will catch it while decoding.
+******************************************************************************/
+
+class OurFileDecoder: public FLAC::Decoder::File {
+public:
+	inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
+
+	bool ignore_metadata_;
+	bool error_occurred_;
+protected:
+	::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+	void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+	void error_callback(::FLAC__StreamDecoderErrorStatus status);
+};
+
+struct OurMetadata {
+	FLAC::Metadata::Prototype *blocks[64];
+	uint32_t num_blocks;
+};
+
+/* our copy of the metadata in flacfilename() */
+static OurMetadata our_metadata_;
+
+/* the current block number that corresponds to the position of the iterator we are testing */
+static uint32_t mc_our_block_number_ = 0;
+
+static const char *flacfilename(bool is_ogg)
+{
+	return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static bool die_(const char *msg)
+{
+	printf("ERROR: %s\n", msg);
+	return false;
+}
+
+static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
+{
+	printf("ERROR: %s\n", msg);
+	printf("       status=%u (%s)\n", (uint32_t)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
+	return false;
+}
+
+static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
+{
+	const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
+	printf("ERROR: %s\n", msg);
+	printf("       status=%u (%s)\n", (uint32_t)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
+	return false;
+}
+
+static void *malloc_or_die_(size_t size)
+{
+	void *x = malloc(size);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size);
+		exit(1);
+	}
+	return x;
+}
+
+static char *strdup_or_die_(const char *s)
+{
+	char *x = strdup(s);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+		exit(1);
+	}
+	return x;
+}
+
+/* functions for working with our metadata copy */
+
+static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, uint32_t position, bool copy)
+{
+	uint32_t i;
+	FLAC::Metadata::Prototype *obj = block;
+	FLAC__ASSERT(position < our_metadata_.num_blocks);
+	if(copy) {
+		if(0 == (obj = FLAC::Metadata::clone(block)))
+			return die_("during FLAC::Metadata::clone()");
+	}
+	delete our_metadata_.blocks[position];
+	our_metadata_.blocks[position] = obj;
+
+	/* set the is_last flags */
+	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+		our_metadata_.blocks[i]->set_is_last(false);
+	our_metadata_.blocks[i]->set_is_last(true);
+
+	return true;
+}
+
+static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, uint32_t position, bool copy)
+{
+	uint32_t i;
+	FLAC::Metadata::Prototype *obj = block;
+	if(copy) {
+		if(0 == (obj = FLAC::Metadata::clone(block)))
+			return die_("during FLAC::Metadata::clone()");
+	}
+	if(position > our_metadata_.num_blocks) {
+		position = our_metadata_.num_blocks;
+	}
+	else {
+		for(i = our_metadata_.num_blocks; i > position; i--)
+			our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
+	}
+	our_metadata_.blocks[position] = obj;
+	our_metadata_.num_blocks++;
+
+	/* set the is_last flags */
+	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+		our_metadata_.blocks[i]->set_is_last(false);
+	our_metadata_.blocks[i]->set_is_last(true);
+
+	return true;
+}
+
+static void delete_from_our_metadata_(uint32_t position)
+{
+	uint32_t i;
+	FLAC__ASSERT(position < our_metadata_.num_blocks);
+	delete our_metadata_.blocks[position];
+	for(i = position; i < our_metadata_.num_blocks - 1; i++)
+		our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
+	our_metadata_.num_blocks--;
+
+	/* set the is_last flags */
+	if(our_metadata_.num_blocks > 0) {
+		for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+			our_metadata_.blocks[i]->set_is_last(false);
+		our_metadata_.blocks[i]->set_is_last(true);
+	}
+}
+
+void add_to_padding_length_(uint32_t indx, int delta)
+{
+	FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[indx]);
+	FLAC__ASSERT(0 != padding);
+	padding->set_length((uint32_t)((int)padding->get_length() + delta));
+}
+
+/*
+ * This wad of functions supports filename- and callback-based chain reading/writing.
+ * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
+ */
+bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+	static const char *tempfile_suffix = ".metadata_edit";
+	size_t destlen = strlen(filename) + strlen(tempfile_suffix) + 1;
+
+	*tempfilename = (char*)malloc(destlen);
+	if (*tempfilename == 0)
+		return false;
+	flac_snprintf(*tempfilename, destlen, "%s%s", filename, tempfile_suffix);
+
+	*tempfile = flac_fopen(*tempfilename, "wb");
+	if (*tempfile == 0)
+		return false;
+
+	return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+	if (*tempfile != 0) {
+		(void)fclose(*tempfile);
+		*tempfile = 0;
+	}
+
+	if (*tempfilename != 0) {
+		(void)flac_unlink(*tempfilename);
+		free(*tempfilename);
+		*tempfilename = 0;
+	}
+}
+
+bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != tempfile);
+	FLAC__ASSERT(0 != tempfilename);
+	FLAC__ASSERT(0 != *tempfilename);
+
+	if(0 != *tempfile) {
+		(void)fclose(*tempfile);
+		*tempfile = 0;
+	}
+
+#if defined _MSC_VER || 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);
+		return false;
+	}
+#endif
+
+	if(0 != flac_rename(*tempfilename, filename)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+
+	cleanup_tempfile_(tempfile, tempfilename);
+
+	return true;
+}
+
+bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+	return (0 == flac_stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+	struct timespec srctime[2] = {};
+	srctime[0].tv_sec = stats->st_atime;
+	srctime[1].tv_sec = stats->st_mtime;
+#else
+	struct utimbuf srctime;
+	srctime.actime = stats->st_atime;
+	srctime.modtime = stats->st_mtime;
+#endif
+	(void)flac_chmod(filename, stats->st_mode);
+	(void)flac_utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+	FLAC_CHECK_RETURN(chown(filename, stats->st_uid, (gid_t)(-1)));
+	FLAC_CHECK_RETURN(chown(filename, (uid_t)(-1), stats->st_gid));
+#endif
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
+{
+	FILE *stream = (FILE*)handle;
+	size_t ret = fwrite(ptr, size, nmemb, stream);
+	if(!ferror(stream))
+		fflush(stream);
+	return ret;
+}
+#endif
+
+static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+	FLAC__off_t o = (FLAC__off_t)offset;
+	FLAC__ASSERT(offset == o);
+	return fseeko((FILE*)handle, o, whence);
+}
+
+static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
+{
+	return ftello((FILE*)handle);
+}
+
+static int chain_eof_cb_(::FLAC__IOHandle handle)
+{
+	return feof((FILE*)handle);
+}
+
+static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
+{
+	if(filename_based)
+		return chain.write(use_padding, preserve_file_stats);
+	else {
+		::FLAC__IOCallbacks callbacks;
+
+		memset(&callbacks, 0, sizeof(callbacks));
+		callbacks.read = (::FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+		callbacks.write = chain_write_cb_;
+#else
+		callbacks.write = (::FLAC__IOCallback_Write)fwrite;
+#endif
+		callbacks.seek = chain_seek_cb_;
+		callbacks.eof = chain_eof_cb_;
+
+		if(chain.check_if_tempfile_needed(use_padding)) {
+			struct flac_stat_s stats;
+			FILE *file, *tempfile;
+			char *tempfilename;
+			if(preserve_file_stats) {
+				if(!get_file_stats_(filename, &stats))
+					return false;
+			}
+			if(0 == (file = flac_fopen(filename, "rb")))
+				return false; /*@@@@ chain status still says OK though */
+			if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
+				fclose(file);
+				cleanup_tempfile_(&tempfile, &tempfilename);
+				return false; /*@@@@ chain status still says OK though */
+			}
+			if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
+				fclose(file);
+				fclose(tempfile);
+				return false;
+			}
+			fclose(file);
+			fclose(tempfile);
+			file = tempfile = 0;
+			if(!transport_tempfile_(filename, &tempfile, &tempfilename))
+				return false;
+			if(preserve_file_stats)
+				set_file_stats_(filename, &stats);
+		}
+		else {
+			FILE *file = flac_fopen(filename, "r+b");
+			if(0 == file)
+				return false; /*@@@@ chain status still says OK though */
+			if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks)) {
+				fclose(file);
+				return false;
+			}
+			fclose(file);
+		}
+	}
+
+	return true;
+}
+
+static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based, bool is_ogg)
+{
+	if(filename_based)
+		return chain.read(filename, is_ogg);
+	else {
+		::FLAC__IOCallbacks callbacks;
+
+		memset(&callbacks, 0, sizeof(callbacks));
+		callbacks.read = (::FLAC__IOCallback_Read)fread;
+		callbacks.seek = chain_seek_cb_;
+		callbacks.tell = chain_tell_cb_;
+
+		{
+			bool ret;
+			FILE *file = flac_fopen(filename, "rb");
+			if(0 == file)
+				return false; /*@@@@ chain status still says OK though */
+			ret = chain.read((::FLAC__IOHandle)file, callbacks, is_ogg);
+			fclose(file);
+			return ret;
+		}
+	}
+}
+
+/* function for comparing our metadata to a FLAC::Metadata::Chain */
+
+static bool compare_chain_(FLAC::Metadata::Chain &chain, uint32_t current_position, FLAC::Metadata::Prototype *current_block)
+{
+	uint32_t i;
+	FLAC::Metadata::Iterator iterator;
+	bool next_ok = true;
+
+	printf("\tcomparing chain... ");
+	fflush(stdout);
+
+	if(!iterator.is_valid())
+		return die_("allocating memory for iterator");
+
+	iterator.init(chain);
+
+	i = 0;
+	do {
+		FLAC::Metadata::Prototype *block;
+
+		printf("%u... ", i);
+		fflush(stdout);
+
+		if(0 == (block = iterator.get_block()))
+			return die_("getting block from iterator");
+
+		if(*block != *our_metadata_.blocks[i])
+			return die_("metadata block mismatch");
+
+		delete block;
+		i++;
+		next_ok = iterator.next();
+	} while(i < our_metadata_.num_blocks && next_ok);
+
+	if(next_ok)
+		return die_("chain has more blocks than expected");
+
+	if(i < our_metadata_.num_blocks)
+		return die_("short block count in chain");
+
+	if(0 != current_block) {
+		printf("CURRENT_POSITION... ");
+		fflush(stdout);
+
+		if(*current_block != *our_metadata_.blocks[current_position])
+			return die_("metadata block mismatch");
+	}
+
+	printf("PASSED\n");
+
+	return true;
+}
+
+::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+	(void)buffer;
+
+	if(
+		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+	) {
+		printf("content... ");
+		fflush(stdout);
+	}
+
+	return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+	/* don't bother checking if we've already hit an error */
+	if(error_occurred_)
+		return;
+
+	printf("%u... ", mc_our_block_number_);
+	fflush(stdout);
+
+	if(!ignore_metadata_) {
+		if(mc_our_block_number_ >= our_metadata_.num_blocks) {
+			(void)die_("got more metadata blocks than expected");
+			error_occurred_ = true;
+		}
+		else {
+			if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
+				(void)die_("metadata block mismatch");
+				error_occurred_ = true;
+			}
+		}
+	}
+
+	mc_our_block_number_++;
+}
+
+void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+	error_occurred_ = true;
+	printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (uint32_t)status);
+}
+
+static bool generate_file_(bool include_extras, bool is_ogg)
+{
+	::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
+	::FLAC__StreamMetadata *metadata[4];
+	uint32_t i = 0, n = 0;
+
+	printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
+
+	while(our_metadata_.num_blocks > 0)
+		delete_from_our_metadata_(0);
+
+	streaminfo.is_last = false;
+	streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
+	streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+	streaminfo.data.stream_info.min_blocksize = 576;
+	streaminfo.data.stream_info.max_blocksize = 576;
+	streaminfo.data.stream_info.min_framesize = 0;
+	streaminfo.data.stream_info.max_framesize = 0;
+	streaminfo.data.stream_info.sample_rate = 44100;
+	streaminfo.data.stream_info.channels = 1;
+	streaminfo.data.stream_info.bits_per_sample = 8;
+	streaminfo.data.stream_info.total_samples = 0;
+	memset(streaminfo.data.stream_info.md5sum, 0, 16);
+
+	{
+		const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING);
+		vorbiscomment.is_last = false;
+		vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
+		vorbiscomment.length = (4 + vendor_string_length) + 4;
+		vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
+		vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+		memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
+		vorbiscomment.data.vorbis_comment.num_comments = 0;
+		vorbiscomment.data.vorbis_comment.comments = 0;
+	}
+
+	{
+		if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
+			return die_("priming our metadata");
+		cuesheet->is_last = false;
+		safe_strncpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN", sizeof(cuesheet->data.cue_sheet.media_catalog_number));
+		cuesheet->data.cue_sheet.lead_in = 123;
+		cuesheet->data.cue_sheet.is_cd = false;
+		if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
+			return die_("priming our metadata");
+		cuesheet->data.cue_sheet.tracks[0].number = 1;
+		if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
+			return die_("priming our metadata");
+	}
+
+	{
+		picture.is_last = false;
+		picture.type = ::FLAC__METADATA_TYPE_PICTURE;
+		picture.length =
+			(
+				FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+				FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+				FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+				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 /* will add the length for the data later */
+			) / 8
+		;
+		picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+		picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
+		picture.length += strlen(picture.data.picture.mime_type);
+		picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+		picture.length += strlen((const char *)picture.data.picture.description);
+		picture.data.picture.width = 300;
+		picture.data.picture.height = 300;
+		picture.data.picture.depth = 24;
+		picture.data.picture.colors = 0;
+		picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+		picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
+		picture.length += picture.data.picture.data_length;
+	}
+
+	padding.is_last = true;
+	padding.type = ::FLAC__METADATA_TYPE_PADDING;
+	padding.length = 1234;
+
+	metadata[n++] = &vorbiscomment;
+	if(include_extras) {
+		metadata[n++] = cuesheet;
+		metadata[n++] = &picture;
+	}
+	metadata[n++] = &padding;
+
+	FLAC::Metadata::StreamInfo s(&streaminfo);
+	FLAC::Metadata::VorbisComment v(&vorbiscomment);
+	FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
+	FLAC::Metadata::Picture pi(&picture);
+	FLAC::Metadata::Padding p(&padding);
+	if(
+		!insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
+		!insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
+		(include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
+		(include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
+		!insert_to_our_metadata_(&p, i++, /*copy=*/true)
+	)
+		return die_("priming our metadata");
+
+	if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
+		return die_("creating the encoded file");
+
+	free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
+	free(picture.data.picture.mime_type);
+	free(picture.data.picture.description);
+	free(picture.data.picture.data);
+
+	return true;
+}
+
+static bool test_file_(bool is_ogg, bool ignore_metadata)
+{
+	const char *filename = flacfilename(is_ogg);
+	OurFileDecoder decoder(ignore_metadata);
+
+	mc_our_block_number_ = 0;
+	decoder.error_occurred_ = false;
+
+	printf("\ttesting '%s'... ", filename);
+	fflush(stdout);
+
+	if(!decoder.is_valid())
+		return die_("couldn't allocate decoder instance");
+
+	decoder.set_md5_checking(true);
+	decoder.set_metadata_respond_all();
+	if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		(void)decoder.finish();
+		return die_("initializing decoder\n");
+	}
+	if(!decoder.process_until_end_of_stream()) {
+		(void)decoder.finish();
+		return die_("decoding file\n");
+	}
+
+	(void)decoder.finish();
+
+	if(decoder.error_occurred_)
+		return false;
+
+	if(mc_our_block_number_ != our_metadata_.num_blocks)
+		return die_("short metadata block count");
+
+	printf("PASSED\n");
+	return true;
+}
+
+static bool change_stats_(const char *filename, bool read_only)
+{
+	if(!grabbag__file_change_stats(filename, read_only))
+		return die_("during grabbag__file_change_stats()");
+
+	return true;
+}
+
+static bool remove_file_(const char *filename)
+{
+	while(our_metadata_.num_blocks > 0)
+		delete_from_our_metadata_(0);
+
+	if(!grabbag__file_remove_file(filename))
+		return die_("removing file");
+
+	return true;
+}
+
+static bool test_level_0_()
+{
+	FLAC::Metadata::StreamInfo streaminfo;
+
+	printf("\n\n++++++ testing level 0 interface\n");
+
+	if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
+		return false;
+
+	printf("testing FLAC::Metadata::get_streaminfo()... ");
+
+	if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo))
+		return die_("during FLAC::Metadata::get_streaminfo()");
+
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(streaminfo.get_channels() != 1)
+		return die_("mismatch in streaminfo.get_channels()");
+	if(streaminfo.get_bits_per_sample() != 8)
+		return die_("mismatch in streaminfo.get_bits_per_sample()");
+	if(streaminfo.get_sample_rate() != 44100)
+		return die_("mismatch in streaminfo.get_sample_rate()");
+	if(streaminfo.get_min_blocksize() != 576)
+		return die_("mismatch in streaminfo.get_min_blocksize()");
+	if(streaminfo.get_max_blocksize() != 576)
+		return die_("mismatch in streaminfo.get_max_blocksize()");
+
+	printf("OK\n");
+
+	{
+		printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
+
+		FLAC::Metadata::VorbisComment *tags = 0;
+
+		if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
+			return die_("during FLAC::Metadata::get_tags()");
+
+		/* check to see if some basic data matches (c.f. generate_file_()) */
+		if(tags->get_num_comments() != 0)
+			return die_("mismatch in tags->get_num_comments()");
+
+		printf("OK\n");
+
+		delete tags;
+	}
+
+	{
+		printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
+
+		FLAC::Metadata::VorbisComment tags;
+
+		if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
+			return die_("during FLAC::Metadata::get_tags()");
+
+		/* check to see if some basic data matches (c.f. generate_file_()) */
+		if(tags.get_num_comments() != 0)
+			return die_("mismatch in tags.get_num_comments()");
+
+		printf("OK\n");
+	}
+
+	{
+		printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
+
+		FLAC::Metadata::CueSheet *cuesheet = 0;
+
+		if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
+			return die_("during FLAC::Metadata::get_cuesheet()");
+
+		/* check to see if some basic data matches (c.f. generate_file_()) */
+		if(cuesheet->get_lead_in() != 123)
+			return die_("mismatch in cuesheet->get_lead_in()");
+
+		printf("OK\n");
+
+		delete cuesheet;
+	}
+
+	{
+		printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
+
+		FLAC::Metadata::CueSheet cuesheet;
+
+		if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
+			return die_("during FLAC::Metadata::get_cuesheet()");
+
+		/* check to see if some basic data matches (c.f. generate_file_()) */
+		if(cuesheet.get_lead_in() != 123)
+			return die_("mismatch in cuesheet.get_lead_in()");
+
+		printf("OK\n");
+	}
+
+	{
+		printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
+
+		FLAC::Metadata::Picture *picture = 0;
+
+		if(!FLAC::Metadata::get_picture(flacfilename(/*is_ogg=*/false), picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-1)))
+			return die_("during FLAC::Metadata::get_picture()");
+
+		/* check to see if some basic data matches (c.f. generate_file_()) */
+		if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+			return die_("mismatch in picture->get_type ()");
+
+		printf("OK\n");
+
+		delete picture;
+	}
+
+	{
+		printf("testing FLAC::Metadata::get_picture(Picture &)... ");
+
+		FLAC::Metadata::Picture picture;
+
+		if(!FLAC::Metadata::get_picture(flacfilename(/*is_ogg=*/false), picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-1)))
+			return die_("during FLAC::Metadata::get_picture()");
+
+		/* check to see if some basic data matches (c.f. generate_file_()) */
+		if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+			return die_("mismatch in picture->get_type ()");
+
+		printf("OK\n");
+	}
+
+	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+		return false;
+
+	return true;
+}
+
+static bool test_level_1_()
+{
+	FLAC::Metadata::Prototype *block;
+	FLAC::Metadata::StreamInfo *streaminfo;
+	FLAC::Metadata::Padding *padding;
+	FLAC::Metadata::Application *app;
+	FLAC__byte data[1000];
+	uint32_t our_current_position = 0;
+
+	// initialize 'data' to avoid Valgrind errors
+	memset(data, 0, sizeof(data));
+
+	printf("\n\n++++++ testing level 1 interface\n");
+
+	/************************************************************/
+	{
+	printf("simple iterator on read-only file\n");
+
+	if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
+		return false;
+
+	if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
+		return false;
+
+	FLAC::Metadata::SimpleIterator iterator;
+
+	if(!iterator.is_valid())
+		return die_("iterator.is_valid() returned false");
+
+	if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+		return die_("iterator.init() returned false");
+
+	printf("is writable = %u\n", (uint32_t)iterator.is_writable());
+	if(iterator.is_writable())
+		return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
+
+	printf("iterate forwards\n");
+
+	if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
+		return die_("expected STREAMINFO type from iterator.get_block_type()");
+	if(0 == (block = iterator.get_block()))
+		return die_("getting block 0");
+	if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
+		return die_("expected STREAMINFO type");
+	if(block->get_is_last())
+		return die_("expected is_last to be false");
+	if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+		return die_("bad STREAMINFO length");
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
+	FLAC__ASSERT(0 != streaminfo);
+	if(streaminfo->get_channels() != 1)
+		return die_("mismatch in channels");
+	if(streaminfo->get_bits_per_sample() != 8)
+		return die_("mismatch in bits_per_sample");
+	if(streaminfo->get_sample_rate() != 44100)
+		return die_("mismatch in sample_rate");
+	if(streaminfo->get_min_blocksize() != 576)
+		return die_("mismatch in min_blocksize");
+	if(streaminfo->get_max_blocksize() != 576)
+		return die_("mismatch in max_blocksize");
+	// we will delete streaminfo a little later when we're really done with it...
+
+	if(!iterator.next())
+		return die_("forward iterator ended early");
+	our_current_position++;
+
+	if(!iterator.next())
+		return die_("forward iterator ended early");
+	our_current_position++;
+
+	if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
+		return die_("expected PADDING type from iterator.get_block_type()");
+	if(0 == (block = iterator.get_block()))
+		return die_("getting block 1");
+	if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
+		return die_("expected PADDING type");
+	if(!block->get_is_last())
+		return die_("expected is_last to be true");
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(block->get_length() != 1234)
+		return die_("bad PADDING length");
+	delete block;
+
+	if(iterator.next())
+		return die_("forward iterator returned true but should have returned false");
+
+	printf("iterate backwards\n");
+	if(!iterator.prev())
+		return die_("reverse iterator ended early");
+	if(!iterator.prev())
+		return die_("reverse iterator ended early");
+	if(iterator.prev())
+		return die_("reverse iterator returned true but should have returned false");
+
+	printf("testing iterator.set_block() on read-only file...\n");
+
+	if(!iterator.set_block(streaminfo, false))
+		printf("PASSED.  iterator.set_block() returned false like it should\n");
+	else
+		return die_("iterator.set_block() returned true but shouldn't have");
+	delete streaminfo;
+	}
+
+	/************************************************************/
+	{
+	printf("simple iterator on writable file\n");
+
+	if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
+		return false;
+
+	printf("creating APPLICATION block\n");
+
+	if(0 == (app = new FLAC::Metadata::Application()))
+		return die_("new FLAC::Metadata::Application()");
+	app->set_id((const uint8_t *)"duh");
+
+	printf("creating PADDING block\n");
+
+	if(0 == (padding = new FLAC::Metadata::Padding())) {
+		delete app;
+		return die_("new FLAC::Metadata::Padding()");
+	}
+	padding->set_length(20);
+
+	FLAC::Metadata::SimpleIterator iterator;
+
+	if(!iterator.is_valid()) {
+		delete app;
+		delete padding;
+		return die_("iterator.is_valid() returned false");
+	}
+
+	if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false)) {
+		delete app;
+		delete padding;
+		return die_("iterator.init() returned false");
+	}
+	our_current_position = 0;
+
+	printf("is writable = %u\n", (uint32_t)iterator.is_writable());
+
+	printf("[S]VP\ttry to write over STREAMINFO block...\n");
+	if(!iterator.set_block(app, false))
+		printf("\titerator.set_block() returned false like it should\n");
+	else {
+		delete app;
+		delete padding;
+		return die_("iterator.set_block() returned true but shouldn't have");
+	}
+
+	printf("[S]VP\tnext\n");
+	if(!iterator.next()) {
+		delete app;
+		delete padding;
+		return die_("iterator ended early\n");
+	}
+	our_current_position++;
+
+	printf("S[V]P\tnext\n");
+	if(!iterator.next()) {
+		delete app;
+		delete padding;
+		return die_("iterator ended early\n");
+	}
+	our_current_position++;
+
+	printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
+	padding->set_length(25);
+	if(!iterator.insert_block_after(padding, false))
+		return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	printf("SVP[P]\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SV[P]P\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
+	padding->set_length(30);
+	if(!iterator.insert_block_after(padding, false))
+		return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[P]PP\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]PPP\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
+	if(iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false) should have returned false", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("[S]VPPP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]PPP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]PP\tdelete (middle block), replace with padding\n");
+	if(!iterator.delete_block(true))
+		return die_ss_("iterator.delete_block(true)", iterator);
+	our_current_position--;
+
+	printf("S[V]PPP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("S[V]PP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]P\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVP[P]\tdelete (last block), replace with padding\n");
+	if(!iterator.delete_block(true))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	our_current_position--;
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[P]P\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVP[P]\tdelete (last block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[P]\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]P\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("[S]VP\tset STREAMINFO (change sample rate)\n");
+	FLAC__ASSERT(our_current_position == 0);
+	block = iterator.get_block();
+	streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
+	FLAC__ASSERT(0 != streaminfo);
+	streaminfo->set_sample_rate(32000);
+	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(block, false))
+		return die_ss_("iterator.set_block(block, false)", iterator);
+	delete block;
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("[S]VP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
+	app->set_id((const uint8_t *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
+	if(!iterator.insert_block_after(app, true))
+		return die_ss_("iterator.insert_block_after(app, true)", iterator);
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return false;
+	add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]P\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
+	app->set_id((const uint8_t *)"fuh"); /* twiddle the id */
+	if(!iterator.set_block(app, true))
+		return die_ss_("iterator.set_block(app, true)", iterator);
+	if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
+		return false;
+	add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
+	app->set_id((const uint8_t *)"guh"); /* twiddle the id */
+	if(!app->set_data(data, sizeof(data), true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app, false))
+		return die_ss_("iterator.set_block(app, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
+	app->set_id((const uint8_t *)"huh"); /* twiddle the id */
+	if(!app->set_data(data, 12, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app, false))
+		return die_ss_("iterator.set_block(app, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
+	app->set_id((const uint8_t *)"iuh"); /* twiddle the id */
+	if(!app->set_data(data, sizeof(data), true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
+	if(!iterator.set_block(app, true))
+		return die_ss_("iterator.set_block(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
+	app->set_id((const uint8_t *)"juh"); /* twiddle the id */
+	if(!app->set_data(data, 23, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
+		return die_("copying object");
+	dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
+	if(!iterator.set_block(app, true))
+		return die_ss_("iterator.set_block(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVA[A]PP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVAA[P]P\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
+	padding->set_length(5);
+	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(padding, false))
+		return die_ss_("iterator.set_block(padding, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVAAP[P]\tset APPLICATION (grow)\n");
+	app->set_id((const uint8_t *)"kuh"); /* twiddle the id */
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app, false))
+		return die_ss_("iterator.set_block(app, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVAAP[A]\tset PADDING (equal)\n");
+	padding->set_length(27);
+	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(padding, false))
+		return die_ss_("iterator.set_block(padding, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVAAP[P]\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]P\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVA[P]\tinsert PADDING after\n");
+	padding->set_length(5);
+	if(!iterator.insert_block_after(padding, false))
+		return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVAP[P]\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SVA[P]P\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
+	if(!app->set_data(data, 32, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app, true))
+		return die_ss_("iterator.set_block(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
+	if(!app->set_data(data, 60, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app, true))
+		return die_ss_("iterator.set_block(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
+	if(!app->set_data(data, 87, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
+	if(!iterator.set_block(app, true))
+		return die_ss_("iterator.set_block(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+	if(!app->set_data(data, 91, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	if(!iterator.set_block(app, true))
+		return die_ss_("iterator.set_block(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+	if(!app->set_data(data, 100, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	our_metadata_.blocks[our_current_position]->set_is_last(true);
+	if(!iterator.set_block(app, true))
+		return die_ss_("iterator.set_block(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]\tset PADDING (equal size)\n");
+	padding->set_length(app->get_length());
+	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(padding, true))
+		return die_ss_("iterator.set_block(padding, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[P]\tinsert PADDING after\n");
+	if(!iterator.insert_block_after(padding, false))
+		return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVP[P]\tinsert PADDING after\n");
+	padding->set_length(5);
+	if(!iterator.insert_block_after(padding, false))
+		return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVPP[P]\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SVP[P]P\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SV[P]PP\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
+	if(!app->set_data(data, 101, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.insert_block_after(app, true))
+		return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
+	if(!app->set_data(data, 97, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.insert_block_after(app, true))
+		return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+	if(!app->set_data(data, 100, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	if(!iterator.insert_block_after(app, true))
+		return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
+	if(!app->set_data(data, 96, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
+	if(!iterator.insert_block_after(app, true))
+		return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("S[V]PP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
+	if(!iterator.delete_block(false))
+		return die_ss_("iterator.delete_block(false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+
+	printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+	if(!app->set_data(data, 1, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	if(!iterator.insert_block_after(app, true))
+		return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+		return false;
+	}
+
+	delete app;
+	delete padding;
+
+	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+		return false;
+
+	return true;
+}
+
+static bool test_level_2_(bool filename_based, bool is_ogg)
+{
+	FLAC::Metadata::Prototype *block;
+	FLAC::Metadata::StreamInfo *streaminfo;
+	FLAC::Metadata::Application *app;
+	FLAC::Metadata::Padding *padding;
+	FLAC__byte data[2000];
+	uint32_t our_current_position;
+
+	// initialize 'data' to avoid Valgrind errors
+	memset(data, 0, sizeof(data));
+
+	printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
+
+	printf("generate read-only file\n");
+
+	if(!generate_file_(/*include_extras=*/false, is_ogg))
+		return false;
+
+	if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
+		return false;
+
+	printf("create chain\n");
+	FLAC::Metadata::Chain chain;
+	if(!chain.is_valid())
+		return die_("allocating memory for chain");
+
+	printf("read chain\n");
+
+	if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
+		return die_c_("reading chain", chain.status());
+
+	printf("[S]VP\ttest initial metadata\n");
+
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	if(is_ogg)
+		goto end;
+
+	printf("switch file to read-write\n");
+
+	if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
+		return false;
+
+	printf("create iterator\n");
+	{
+	FLAC::Metadata::Iterator iterator;
+	if(!iterator.is_valid())
+		return die_("allocating memory for iterator");
+
+	our_current_position = 0;
+
+	iterator.init(chain);
+
+	if(0 == (block = iterator.get_block()))
+		return die_("getting block from iterator");
+
+	FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
+
+	printf("[S]VP\tmodify STREAMINFO, write\n");
+
+	streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
+	FLAC__ASSERT(0 != streaminfo);
+	streaminfo->set_sample_rate(32000);
+	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete block;
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(false, true)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("[S]VP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]P\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
+	if(0 == (block = iterator.get_block()))
+		return die_("getting block from iterator");
+	if(0 == (app = new FLAC::Metadata::Application()))
+		return die_("new FLAC::Metadata::Application()");
+	app->set_id((const uint8_t *)"duh");
+	if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
+		return die_("setting APPLICATION data");
+	delete block;
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(false, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]\tshrink APPLICATION, don't use padding\n");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 26, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(false, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]\tgrow APPLICATION, don't use padding\n");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 28, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(false, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 36, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(false, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 33, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(true, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
+	if(0 == (padding = new FLAC::Metadata::Padding()))
+		return die_("creating PADDING block");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 29, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	padding->set_length(0);
+	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
+		return die_("internal error");
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(true, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 16, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(true, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 50, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(true, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 56, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	add_to_padding_length_(our_current_position+1, -(56 - 50));
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(true, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
+	if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("copying object");
+	if(!app->set_data(data, 67, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	if(!iterator.set_block(app))
+		return die_c_("iterator.set_block(app)", chain.status());
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(true, false)", chain.status());
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV[A]\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]A\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
+	if(0 == (padding = new FLAC::Metadata::Padding()))
+		return die_("creating PADDING block");
+	padding->set_length(30);
+	if(!iterator.insert_block_before(padding))
+		printf("\titerator.insert_block_before() returned false like it should\n");
+	else
+		return die_("iterator.insert_block_before() should have returned false");
+
+	printf("[S]VA\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]A\tinsert PADDING after\n");
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!iterator.insert_block_after(padding))
+		return die_("iterator.insert_block_after(padding)");
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	printf("SV[P]A\tinsert PADDING before\n");
+	if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("creating PADDING block");
+	padding->set_length(17);
+	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!iterator.insert_block_before(padding))
+		return die_("iterator.insert_block_before(padding)");
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	printf("SV[P]PA\tinsert PADDING before\n");
+	if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+		return die_("creating PADDING block");
+	padding->set_length(0);
+	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!iterator.insert_block_before(padding))
+		return die_("iterator.insert_block_before(padding)");
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	printf("SV[P]PPA\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVP[P]PA\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVPP[P]A\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVPPP[A]\tinsert PADDING after\n");
+	if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
+		return die_("creating PADDING block");
+	padding->set_length(57);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!iterator.insert_block_after(padding))
+		return die_("iterator.insert_block_after(padding)");
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	printf("SVPPPA[P]\tinsert PADDING before\n");
+	if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
+		return die_("creating PADDING block");
+	padding->set_length(99);
+	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!iterator.insert_block_before(padding))
+		return die_("iterator.insert_block_before(padding)");
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	}
+	our_current_position = 0;
+
+	printf("SVPPPAPP\tmerge padding\n");
+	chain.merge_padding();
+	add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
+	add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
+	add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
+	delete_from_our_metadata_(7);
+	delete_from_our_metadata_(4);
+	delete_from_our_metadata_(3);
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(true, false)", chain.status());
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SVPAP\tsort padding\n");
+	chain.sort_padding();
+	add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
+	delete_from_our_metadata_(2);
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(true, false)", chain.status());
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("create iterator\n");
+	{
+	FLAC::Metadata::Iterator iterator;
+	if(!iterator.is_valid())
+		return die_("allocating memory for iterator");
+
+	our_current_position = 0;
+
+	iterator.init(chain);
+
+	printf("[S]VAP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]AP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[A]P\tdelete middle block, replace with padding\n");
+	if(0 == (padding = new FLAC::Metadata::Padding()))
+		return die_("creating PADDING block");
+	padding->set_length(71);
+	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+		return die_("copying object");
+	if(!iterator.delete_block(/*replace_with_padding=*/true))
+		return die_c_("iterator.delete_block(true)", chain.status());
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	printf("S[V]PP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]P\tdelete middle block, don't replace with padding\n");
+	delete_from_our_metadata_(our_current_position--);
+	if(!iterator.delete_block(/*replace_with_padding=*/false))
+		return die_c_("iterator.delete_block(false)", chain.status());
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	printf("S[V]P\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]\tdelete last block, replace with padding\n");
+	if(0 == (padding = new FLAC::Metadata::Padding()))
+		return die_("creating PADDING block");
+	padding->set_length(219);
+	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+		return die_("copying object");
+	if(!iterator.delete_block(/*replace_with_padding=*/true))
+		return die_c_("iterator.delete_block(true)", chain.status());
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	printf("S[V]P\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]\tdelete last block, don't replace with padding\n");
+	delete_from_our_metadata_(our_current_position--);
+	if(!iterator.delete_block(/*replace_with_padding=*/false))
+		return die_c_("iterator.delete_block(false)", chain.status());
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	printf("S[V]\tprev\n");
+	if(!iterator.prev())
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("[S]V\tdelete STREAMINFO block, should fail\n");
+	if(iterator.delete_block(/*replace_with_padding=*/false))
+		return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
+
+	block = iterator.get_block();
+	if(!compare_chain_(chain, our_current_position, block))
+		return false;
+	delete block;
+
+	} // delete iterator
+	our_current_position = 0;
+
+	printf("SV\tmerge padding\n");
+	chain.merge_padding();
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(false, false)", chain.status());
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+	printf("SV\tsort padding\n");
+	chain.sort_padding();
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during chain.write(false, false)", chain.status());
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+		return false;
+
+end:
+	if(!remove_file_(flacfilename(is_ogg)))
+		return false;
+
+	return true;
+}
+
+static bool test_level_2_misc_(bool is_ogg)
+{
+	::FLAC__IOCallbacks callbacks;
+
+	memset(&callbacks, 0, sizeof(callbacks));
+	callbacks.read = (::FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+	callbacks.write = chain_write_cb_;
+#else
+	callbacks.write = (::FLAC__IOCallback_Write)fwrite;
+#endif
+	callbacks.seek = chain_seek_cb_;
+	callbacks.tell = chain_tell_cb_;
+	callbacks.eof = chain_eof_cb_;
+
+	printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
+
+	printf("generate file\n");
+
+	if(!generate_file_(/*include_extras=*/false, is_ogg))
+		return false;
+
+	printf("create chain\n");
+	FLAC::Metadata::Chain chain;
+	if(!chain.is_valid())
+		return die_("allocating chain");
+
+	printf("read chain (filename-based)\n");
+
+	if(!chain.read(flacfilename(is_ogg)))
+		return die_c_("reading chain", chain.status());
+
+	printf("write chain with wrong method Chain::write(with callbacks)\n");
+	{
+		if(chain.write(/*use_padding=*/false, 0, callbacks))
+			return die_c_("mismatched write should have failed", chain.status());
+		if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
+		printf("  OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+	}
+
+	printf("read chain (filename-based)\n");
+
+	if(!chain.read(flacfilename(is_ogg)))
+		return die_c_("reading chain", chain.status());
+
+	printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
+	{
+		if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
+			return die_c_("mismatched write should have failed", chain.status());
+		if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
+		printf("  OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+	}
+
+	printf("read chain (callback-based)\n");
+	{
+		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
+		if(0 == file)
+			return die_("opening file");
+		if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
+			fclose(file);
+			return die_c_("reading chain", chain.status());
+		}
+		fclose(file);
+	}
+
+	printf("write chain with wrong method write()\n");
+	{
+		if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
+			return die_c_("mismatched write should have failed", chain.status());
+		if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
+		printf("  OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+	}
+
+	printf("read chain (callback-based)\n");
+	{
+		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
+		if(0 == file)
+			return die_("opening file");
+		if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
+			fclose(file);
+			return die_c_("reading chain", chain.status());
+		}
+		fclose(file);
+	}
+
+	printf("testing Chain::check_if_tempfile_needed()... ");
+
+	if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
+		printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
+	else
+		return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
+
+	printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
+	{
+		if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
+			return die_c_("mismatched write should have failed", chain.status());
+		if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
+		printf("  OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+	}
+
+	printf("read chain (callback-based)\n");
+	{
+		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
+		if(0 == file)
+			return die_("opening file");
+		if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
+			fclose(file);
+			return die_c_("reading chain", chain.status());
+		}
+		fclose(file);
+	}
+
+	printf("create iterator\n");
+	{
+	FLAC::Metadata::Iterator iterator;
+	if(!iterator.is_valid())
+		return die_("allocating memory for iterator");
+
+	iterator.init(chain);
+
+	printf("[S]VP\tnext\n");
+	if(!iterator.next())
+		return die_("iterator ended early\n");
+
+	printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
+	if(!iterator.delete_block(/*replace_with_padding=*/false))
+		return die_c_("block delete failed\n", chain.status());
+
+	printf("testing Chain::check_if_tempfile_needed()... ");
+
+	if(chain.check_if_tempfile_needed(/*use_padding=*/false))
+		printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
+	else
+		return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
+
+	printf("write chain with wrong method Chain::write(with callbacks)\n");
+	{
+		if(chain.write(/*use_padding=*/false, 0, callbacks))
+			return die_c_("mismatched write should have failed", chain.status());
+		if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
+		printf("  OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+	}
+
+	} // delete iterator
+
+	if(!remove_file_(flacfilename(is_ogg)))
+		return false;
+
+	return true;
+}
+
+bool test_metadata_file_manipulation()
+{
+	printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
+
+	our_metadata_.num_blocks = 0;
+
+	if(!test_level_0_())
+		return false;
+
+	if(!test_level_1_())
+		return false;
+
+	if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
+		return false;
+	if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
+		return false;
+	if(!test_level_2_misc_(/*is_ogg=*/false))
+		return false;
+
+	if(FLAC_API_SUPPORTS_OGG_FLAC) {
+		if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
+			return false;
+		if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
+			return false;
+#if 0
+		/* when ogg flac write is supported, will have to add this: */
+		if(!test_level_2_misc_(/*is_ogg=*/true))
+			return false;
+#endif
+	}
+
+	return true;
+}
diff --git a/src/test_libFLAC++/metadata_object.cpp b/src/test_libFLAC++/metadata_object.cpp
new file mode 100644
index 0000000..d46c1c2
--- /dev/null
+++ b/src/test_libFLAC++/metadata_object.cpp
@@ -0,0 +1,2099 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+#include "FLAC/assert.h"
+#include "FLAC++/metadata.h"
+#include "share/safe_str.h"
+
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application_, vorbiscomment_, cuesheet_, picture_;
+
+static bool die_(const char *msg)
+{
+	printf("FAILED, %s\n", msg);
+	return false;
+}
+
+static void *malloc_or_die_(size_t size)
+{
+	void *x = malloc(size);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size);
+		exit(1);
+	}
+	return x;
+}
+
+static char *strdup_or_die_(const char *s)
+{
+	char *x = strdup(s);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+		exit(1);
+	}
+	return x;
+}
+
+static bool index_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Index &indx, const ::FLAC__StreamMetadata_CueSheet_Index &indxcopy)
+{
+	if(indxcopy.offset != indx.offset)
+		return false;
+	if(indxcopy.number != indx.number)
+		return false;
+	return true;
+}
+
+static bool track_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Track *track, const ::FLAC__StreamMetadata_CueSheet_Track *trackcopy)
+{
+	uint32_t i;
+
+	if(trackcopy->offset != track->offset)
+		return false;
+	if(trackcopy->number != track->number)
+		return false;
+	if(0 != strcmp(trackcopy->isrc, track->isrc))
+		return false;
+	if(trackcopy->type != track->type)
+		return false;
+	if(trackcopy->pre_emphasis != track->pre_emphasis)
+		return false;
+	if(trackcopy->num_indices != track->num_indices)
+		return false;
+	if(0 == track->indices || 0 == trackcopy->indices) {
+		if(track->indices != trackcopy->indices)
+			return false;
+	}
+	else {
+		for(i = 0; i < track->num_indices; i++) {
+			if(!index_is_equal_(trackcopy->indices[i], track->indices[i]))
+				return false;
+		}
+	}
+	return true;
+}
+
+static void init_metadata_blocks_()
+{
+	streaminfo_.is_last = false;
+	streaminfo_.type = ::FLAC__METADATA_TYPE_STREAMINFO;
+	streaminfo_.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+	streaminfo_.data.stream_info.min_blocksize = 576;
+	streaminfo_.data.stream_info.max_blocksize = 576;
+	streaminfo_.data.stream_info.min_framesize = 0;
+	streaminfo_.data.stream_info.max_framesize = 0;
+	streaminfo_.data.stream_info.sample_rate = 44100;
+	streaminfo_.data.stream_info.channels = 1;
+	streaminfo_.data.stream_info.bits_per_sample = 8;
+	streaminfo_.data.stream_info.total_samples = 0;
+	memset(streaminfo_.data.stream_info.md5sum, 0, 16);
+
+	padding_.is_last = false;
+	padding_.type = ::FLAC__METADATA_TYPE_PADDING;
+	padding_.length = 1234;
+
+	seektable_.is_last = false;
+	seektable_.type = ::FLAC__METADATA_TYPE_SEEKTABLE;
+	seektable_.data.seek_table.num_points = 2;
+	seektable_.length = seektable_.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+	seektable_.data.seek_table.points = (::FLAC__StreamMetadata_SeekPoint*)malloc_or_die_(seektable_.data.seek_table.num_points * sizeof(::FLAC__StreamMetadata_SeekPoint));
+	seektable_.data.seek_table.points[0].sample_number = 0;
+	seektable_.data.seek_table.points[0].stream_offset = 0;
+	seektable_.data.seek_table.points[0].frame_samples = streaminfo_.data.stream_info.min_blocksize;
+	seektable_.data.seek_table.points[1].sample_number = ::FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+	seektable_.data.seek_table.points[1].stream_offset = 1000;
+	seektable_.data.seek_table.points[1].frame_samples = streaminfo_.data.stream_info.min_blocksize;
+
+	application_.is_last = false;
+	application_.type = ::FLAC__METADATA_TYPE_APPLICATION;
+	application_.length = 8;
+	memcpy(application_.data.application.id, "\xfe\xdc\xba\x98", 4);
+	application_.data.application.data = (FLAC__byte*)malloc_or_die_(4);
+	memcpy(application_.data.application.data, "\xf0\xe1\xd2\xc3", 4);
+
+	vorbiscomment_.is_last = false;
+	vorbiscomment_.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
+	vorbiscomment_.length = (4 + 5) + 4 + (4 + 12) + (4 + 12);
+	vorbiscomment_.data.vorbis_comment.vendor_string.length = 5;
+	vorbiscomment_.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(5+1);
+	memcpy(vorbiscomment_.data.vorbis_comment.vendor_string.entry, "name0", 5+1);
+	vorbiscomment_.data.vorbis_comment.num_comments = 2;
+	vorbiscomment_.data.vorbis_comment.comments = (::FLAC__StreamMetadata_VorbisComment_Entry*)malloc_or_die_(vorbiscomment_.data.vorbis_comment.num_comments * sizeof(::FLAC__StreamMetadata_VorbisComment_Entry));
+	vorbiscomment_.data.vorbis_comment.comments[0].length = 12;
+	vorbiscomment_.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(12+1);
+	memcpy(vorbiscomment_.data.vorbis_comment.comments[0].entry, "name2=value2", 12+1);
+	vorbiscomment_.data.vorbis_comment.comments[1].length = 12;
+	vorbiscomment_.data.vorbis_comment.comments[1].entry = (FLAC__byte*)malloc_or_die_(12+1);
+	memcpy(vorbiscomment_.data.vorbis_comment.comments[1].entry, "name3=value3", 12+1);
+
+	cuesheet_.is_last = false;
+	cuesheet_.type = ::FLAC__METADATA_TYPE_CUESHEET;
+	cuesheet_.length =
+		/* cuesheet guts */
+		(
+			FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+		) / 8 +
+		/* 2 tracks */
+		2 * (
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+		) / 8 +
+		/* 3 index points */
+		3 * (
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+		) / 8
+	;
+	memset(cuesheet_.data.cue_sheet.media_catalog_number, 0, sizeof(cuesheet_.data.cue_sheet.media_catalog_number));
+	cuesheet_.data.cue_sheet.media_catalog_number[0] = 'j';
+	cuesheet_.data.cue_sheet.media_catalog_number[1] = 'C';
+	cuesheet_.data.cue_sheet.lead_in = 159;
+	cuesheet_.data.cue_sheet.is_cd = true;
+	cuesheet_.data.cue_sheet.num_tracks = 2;
+	cuesheet_.data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)malloc_or_die_(cuesheet_.data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track));
+	cuesheet_.data.cue_sheet.tracks[0].offset = 1;
+	cuesheet_.data.cue_sheet.tracks[0].number = 1;
+	memcpy(cuesheet_.data.cue_sheet.tracks[0].isrc, "ACBDE1234567", sizeof(cuesheet_.data.cue_sheet.tracks[0].isrc));
+	cuesheet_.data.cue_sheet.tracks[0].type = 0;
+	cuesheet_.data.cue_sheet.tracks[0].pre_emphasis = 1;
+	cuesheet_.data.cue_sheet.tracks[0].num_indices = 2;
+	cuesheet_.data.cue_sheet.tracks[0].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet_.data.cue_sheet.tracks[0].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+	cuesheet_.data.cue_sheet.tracks[0].indices[0].offset = 0;
+	cuesheet_.data.cue_sheet.tracks[0].indices[0].number = 0;
+	cuesheet_.data.cue_sheet.tracks[0].indices[1].offset = 1234567890;
+	cuesheet_.data.cue_sheet.tracks[0].indices[1].number = 1;
+	cuesheet_.data.cue_sheet.tracks[1].offset = 2345678901u;
+	cuesheet_.data.cue_sheet.tracks[1].number = 2;
+	memcpy(cuesheet_.data.cue_sheet.tracks[1].isrc, "ACBDE7654321", sizeof(cuesheet_.data.cue_sheet.tracks[1].isrc));
+	cuesheet_.data.cue_sheet.tracks[1].type = 1;
+	cuesheet_.data.cue_sheet.tracks[1].pre_emphasis = 0;
+	cuesheet_.data.cue_sheet.tracks[1].num_indices = 1;
+	cuesheet_.data.cue_sheet.tracks[1].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet_.data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+	cuesheet_.data.cue_sheet.tracks[1].indices[0].offset = 0;
+	cuesheet_.data.cue_sheet.tracks[1].indices[0].number = 1;
+
+	picture_.is_last = true;
+	picture_.type = FLAC__METADATA_TYPE_PICTURE;
+	picture_.length =
+		(
+			FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+			FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+			FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+			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 /* will add the length for the data later */
+		) / 8
+	;
+	picture_.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+	picture_.data.picture.mime_type = strdup_or_die_("image/jpeg");
+	picture_.length += strlen(picture_.data.picture.mime_type);
+	picture_.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+	picture_.length += strlen((const char *)picture_.data.picture.description);
+	picture_.data.picture.width = 300;
+	picture_.data.picture.height = 300;
+	picture_.data.picture.depth = 24;
+	picture_.data.picture.colors = 0;
+	picture_.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+	picture_.data.picture.data_length = strlen((const char *)picture_.data.picture.data);
+	picture_.length += picture_.data.picture.data_length;
+}
+
+static void free_metadata_blocks_()
+{
+	free(seektable_.data.seek_table.points);
+	free(application_.data.application.data);
+	free(vorbiscomment_.data.vorbis_comment.vendor_string.entry);
+	free(vorbiscomment_.data.vorbis_comment.comments[0].entry);
+	free(vorbiscomment_.data.vorbis_comment.comments[1].entry);
+	free(vorbiscomment_.data.vorbis_comment.comments);
+	free(cuesheet_.data.cue_sheet.tracks[0].indices);
+	free(cuesheet_.data.cue_sheet.tracks[1].indices);
+	free(cuesheet_.data.cue_sheet.tracks);
+	free(picture_.data.picture.mime_type);
+	free(picture_.data.picture.description);
+	free(picture_.data.picture.data);
+}
+
+bool test_metadata_object_streaminfo()
+{
+	uint32_t expected_length;
+
+	printf("testing class FLAC::Metadata::StreamInfo\n");
+
+	printf("testing StreamInfo::StreamInfo()... ");
+	FLAC::Metadata::StreamInfo block;
+	if(!block.is_valid())
+		return die_("!block.is_valid()");
+	expected_length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+	if(block.get_length() != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing StreamInfo::StreamInfo(const StreamInfo &)... +\n");
+	printf("        StreamInfo::operator!=(const StreamInfo &)... ");
+	{
+		FLAC::Metadata::StreamInfo blockcopy(block);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != block)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+
+		printf("testing StreamInfo::~StreamInfo()... ");
+	}
+	printf("OK\n");
+
+	printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::StreamInfo blockcopy(streaminfo_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != streaminfo_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::StreamInfo blockcopy(&streaminfo_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != streaminfo_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::StreamInfo blockcopy(&streaminfo_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != streaminfo_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&streaminfo_);
+		FLAC::Metadata::StreamInfo blockcopy(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != streaminfo_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::StreamInfo blockcopy;
+		blockcopy.assign(&streaminfo_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != streaminfo_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&streaminfo_);
+		FLAC::Metadata::StreamInfo blockcopy;
+		blockcopy.assign(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != streaminfo_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::operator=(const StreamInfo &)... +\n");
+	printf("        StreamInfo::operator==(const StreamInfo &)... ");
+	{
+		FLAC::Metadata::StreamInfo blockcopy = block;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == block))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::operator=(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        StreamInfo::operator==(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::StreamInfo blockcopy = streaminfo_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == streaminfo_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::operator=(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        StreamInfo::operator==(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::StreamInfo blockcopy = &streaminfo_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == streaminfo_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing StreamInfo::set_min_blocksize()... ");
+	block.set_min_blocksize(streaminfo_.data.stream_info.min_blocksize);
+	printf("OK\n");
+
+	printf("testing StreamInfo::set_max_blocksize()... ");
+	block.set_max_blocksize(streaminfo_.data.stream_info.max_blocksize);
+	printf("OK\n");
+
+	printf("testing StreamInfo::set_min_framesize()... ");
+	block.set_min_framesize(streaminfo_.data.stream_info.min_framesize);
+	printf("OK\n");
+
+	printf("testing StreamInfo::set_max_framesize()... ");
+	block.set_max_framesize(streaminfo_.data.stream_info.max_framesize);
+	printf("OK\n");
+
+	printf("testing StreamInfo::set_sample_rate()... ");
+	block.set_sample_rate(streaminfo_.data.stream_info.sample_rate);
+	printf("OK\n");
+
+	printf("testing StreamInfo::set_channels()... ");
+	block.set_channels(streaminfo_.data.stream_info.channels);
+	printf("OK\n");
+
+	printf("testing StreamInfo::set_bits_per_sample()... ");
+	block.set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample);
+	printf("OK\n");
+
+	printf("testing StreamInfo::set_total_samples()... ");
+	block.set_total_samples(streaminfo_.data.stream_info.total_samples);
+	printf("OK\n");
+
+	printf("testing StreamInfo::set_md5sum()... ");
+	block.set_md5sum(streaminfo_.data.stream_info.md5sum);
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_min_blocksize()... ");
+	if(block.get_min_blocksize() != streaminfo_.data.stream_info.min_blocksize)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_max_blocksize()... ");
+	if(block.get_max_blocksize() != streaminfo_.data.stream_info.max_blocksize)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_min_framesize()... ");
+	if(block.get_min_framesize() != streaminfo_.data.stream_info.min_framesize)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_max_framesize()... ");
+	if(block.get_max_framesize() != streaminfo_.data.stream_info.max_framesize)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_sample_rate()... ");
+	if(block.get_sample_rate() != streaminfo_.data.stream_info.sample_rate)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_channels()... ");
+	if(block.get_channels() != streaminfo_.data.stream_info.channels)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_bits_per_sample()... ");
+	if(block.get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_total_samples()... ");
+	if(block.get_total_samples() != streaminfo_.data.stream_info.total_samples)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing StreamInfo::get_md5sum()... ");
+	if(0 != memcmp(block.get_md5sum(), streaminfo_.data.stream_info.md5sum, 16))
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+	FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+	if(0 == clone_)
+		return die_("returned NULL");
+	if(0 == dynamic_cast<FLAC::Metadata::StreamInfo *>(clone_))
+		return die_("downcast is NULL");
+	if(*dynamic_cast<FLAC::Metadata::StreamInfo *>(clone_) != block)
+		return die_("clone is not identical");
+	printf("OK\n");
+	printf("testing StreamInfo::~StreamInfo()... ");
+	delete clone_;
+	printf("OK\n");
+
+
+	printf("PASSED\n\n");
+	return true;
+}
+
+bool test_metadata_object_padding()
+{
+	uint32_t expected_length;
+
+	printf("testing class FLAC::Metadata::Padding\n");
+
+	printf("testing Padding::Padding()... ");
+	FLAC::Metadata::Padding block;
+	if(!block.is_valid())
+		return die_("!block.is_valid()");
+	expected_length = 0;
+	if(block.get_length() != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing Padding::Padding(const Padding &)... +\n");
+	printf("        Padding::operator!=(const Padding &)... ");
+	{
+		FLAC::Metadata::Padding blockcopy(block);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != block)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+
+		printf("testing Padding::~Padding()... ");
+	}
+	printf("OK\n");
+
+	printf("testing Padding::Padding(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        Padding::operator!=(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::Padding blockcopy(padding_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != padding_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::Padding(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Padding blockcopy(&padding_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != padding_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::Padding(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Padding blockcopy(&padding_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != padding_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::Padding(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&padding_);
+		FLAC::Metadata::Padding blockcopy(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != padding_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Padding blockcopy;
+		blockcopy.assign(&padding_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != padding_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&padding_);
+		FLAC::Metadata::Padding blockcopy;
+		blockcopy.assign(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != padding_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::operator=(const Padding &)... +\n");
+	printf("        Padding::operator==(const Padding &)... ");
+	{
+		FLAC::Metadata::Padding blockcopy = block;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == block))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::operator=(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        Padding::operator==(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::Padding blockcopy = padding_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == padding_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::operator=(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        Padding::operator==(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Padding blockcopy = &padding_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == padding_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Padding::set_length()... ");
+	block.set_length(padding_.length);
+	printf("OK\n");
+
+	printf("testing Prototype::get_length()... ");
+	if(block.get_length() != padding_.length)
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+	FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+	if(0 == clone_)
+		return die_("returned NULL");
+	if(0 == dynamic_cast<FLAC::Metadata::Padding *>(clone_))
+		return die_("downcast is NULL");
+	if(*dynamic_cast<FLAC::Metadata::Padding *>(clone_) != block)
+		return die_("clone is not identical");
+	printf("OK\n");
+	printf("testing Padding::~Padding()... ");
+	delete clone_;
+	printf("OK\n");
+
+
+	printf("PASSED\n\n");
+	return true;
+}
+
+bool test_metadata_object_application()
+{
+	uint32_t expected_length;
+
+	printf("testing class FLAC::Metadata::Application\n");
+
+	printf("testing Application::Application()... ");
+	FLAC::Metadata::Application block;
+	if(!block.is_valid())
+		return die_("!block.is_valid()");
+	expected_length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+	if(block.get_length() != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing Application::Application(const Application &)... +\n");
+	printf("        Application::operator!=(const Application &)... ");
+	{
+		FLAC::Metadata::Application blockcopy(block);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != block)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+
+		printf("testing Application::~Application()... ");
+	}
+	printf("OK\n");
+
+	printf("testing Application::Application(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        Application::operator!=(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::Application blockcopy(application_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != application_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::Application(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Application blockcopy(&application_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != application_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::Application(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Application blockcopy(&application_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != application_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::Application(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&application_);
+		FLAC::Metadata::Application blockcopy(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != application_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Application blockcopy;
+		blockcopy.assign(&application_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != application_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&application_);
+		FLAC::Metadata::Application blockcopy;
+		blockcopy.assign(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != application_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::operator=(const Application &)... +\n");
+	printf("        Application::operator==(const Application &)... ");
+	{
+		FLAC::Metadata::Application blockcopy = block;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == block))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::operator=(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        Application::operator==(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::Application blockcopy = application_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == application_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::operator=(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        Application::operator==(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Application blockcopy = &application_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == application_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Application::set_id()... ");
+	block.set_id(application_.data.application.id);
+	printf("OK\n");
+
+	printf("testing Application::set_data()... ");
+	block.set_data(application_.data.application.data, application_.length - sizeof(application_.data.application.id), /*copy=*/true);
+	printf("OK\n");
+
+	printf("testing Application::get_id()... ");
+	if(0 != memcmp(block.get_id(), application_.data.application.id, sizeof(application_.data.application.id)))
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing Application::get_data()... ");
+	if(0 != memcmp(block.get_data(), application_.data.application.data, application_.length - sizeof(application_.data.application.id)))
+		return die_("value mismatch, doesn't match previously set value");
+	printf("OK\n");
+
+	printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+	FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+	if(0 == clone_)
+		return die_("returned NULL");
+	if(0 == dynamic_cast<FLAC::Metadata::Application *>(clone_))
+		return die_("downcast is NULL");
+	if(*dynamic_cast<FLAC::Metadata::Application *>(clone_) != block)
+		return die_("clone is not identical");
+	printf("OK\n");
+	printf("testing Application::~Application()... ");
+	delete clone_;
+	printf("OK\n");
+
+
+	printf("PASSED\n\n");
+	return true;
+}
+
+bool test_metadata_object_seektable()
+{
+	uint32_t expected_length;
+
+	printf("testing class FLAC::Metadata::SeekTable\n");
+
+	printf("testing SeekTable::SeekTable()... ");
+	FLAC::Metadata::SeekTable block;
+	if(!block.is_valid())
+		return die_("!block.is_valid()");
+	expected_length = 0;
+	if(block.get_length() != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing SeekTable::SeekTable(const SeekTable &)... +\n");
+	printf("        SeekTable::operator!=(const SeekTable &)... ");
+	{
+		FLAC::Metadata::SeekTable blockcopy(block);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != block)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+
+		printf("testing SeekTable::~SeekTable()... ");
+	}
+	printf("OK\n");
+
+	printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::SeekTable blockcopy(seektable_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != seektable_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::SeekTable blockcopy(&seektable_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != seektable_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::SeekTable blockcopy(&seektable_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != seektable_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&seektable_);
+		FLAC::Metadata::SeekTable blockcopy(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != seektable_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::SeekTable blockcopy;
+		blockcopy.assign(&seektable_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != seektable_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&seektable_);
+		FLAC::Metadata::SeekTable blockcopy;
+		blockcopy.assign(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != seektable_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::operator=(const SeekTable &)... +\n");
+	printf("        SeekTable::operator==(const SeekTable &)... ");
+	{
+		FLAC::Metadata::SeekTable blockcopy = block;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == block))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::operator=(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        SeekTable::operator==(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::SeekTable blockcopy = seektable_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == seektable_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::operator=(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        SeekTable::operator==(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::SeekTable blockcopy = &seektable_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == seektable_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing SeekTable::insert_point() x 3... ");
+	if(!block.insert_point(0, seektable_.data.seek_table.points[1]))
+		return die_("returned false");
+	if(!block.insert_point(0, seektable_.data.seek_table.points[1]))
+		return die_("returned false");
+	if(!block.insert_point(1, seektable_.data.seek_table.points[0]))
+		return die_("returned false");
+	printf("OK\n");
+
+	printf("testing SeekTable::is_legal()... ");
+	if(block.is_legal())
+		return die_("returned true");
+	printf("OK\n");
+
+	printf("testing SeekTable::set_point()... ");
+	block.set_point(0, seektable_.data.seek_table.points[0]);
+	printf("OK\n");
+
+	printf("testing SeekTable::delete_point()... ");
+	if(!block.delete_point(0))
+		return die_("returned false");
+	printf("OK\n");
+
+	printf("testing SeekTable::is_legal()... ");
+	if(!block.is_legal())
+		return die_("returned false");
+	printf("OK\n");
+
+	printf("testing SeekTable::get_num_points()... ");
+	if(block.get_num_points() != seektable_.data.seek_table.num_points)
+		return die_("number mismatch");
+	printf("OK\n");
+
+	printf("testing SeekTable::operator!=(const ::FLAC__StreamMetadata &)... ");
+	if(block != seektable_)
+		return die_("data mismatch");
+	printf("OK\n");
+
+	printf("testing SeekTable::get_point()... ");
+	if(
+		block.get_point(1).sample_number != seektable_.data.seek_table.points[1].sample_number ||
+		block.get_point(1).stream_offset != seektable_.data.seek_table.points[1].stream_offset ||
+		block.get_point(1).frame_samples != seektable_.data.seek_table.points[1].frame_samples
+	)
+		return die_("point mismatch");
+	printf("OK\n");
+
+	printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+	FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+	if(0 == clone_)
+		return die_("returned NULL");
+	if(0 == dynamic_cast<FLAC::Metadata::SeekTable *>(clone_))
+		return die_("downcast is NULL");
+	if(*dynamic_cast<FLAC::Metadata::SeekTable *>(clone_) != block)
+		return die_("clone is not identical");
+	printf("OK\n");
+	printf("testing SeekTable::~SeekTable()... ");
+	delete clone_;
+	printf("OK\n");
+
+
+	printf("PASSED\n\n");
+	return true;
+}
+
+bool test_metadata_object_vorbiscomment()
+{
+	uint32_t expected_length;
+
+	printf("testing class FLAC::Metadata::VorbisComment::Entry\n");
+
+	printf("testing Entry::Entry()... ");
+	{
+		FLAC::Metadata::VorbisComment::Entry entry1;
+		if(!entry1.is_valid())
+			return die_("!is_valid()");
+		printf("OK\n");
+
+		printf("testing Entry::~Entry()... ");
+	}
+	printf("OK\n");
+
+	printf("testing Entry::Entry(const char *field, uint32_t field_length)... ");
+	FLAC::Metadata::VorbisComment::Entry entry2("name2=value2", strlen("name2=value2"));
+	if(!entry2.is_valid())
+		return die_("!is_valid()");
+	printf("OK\n");
+
+	{
+		printf("testing Entry::Entry(const char *field)... ");
+		FLAC::Metadata::VorbisComment::Entry entry2z("name2=value2");
+		if(!entry2z.is_valid())
+			return die_("!is_valid()");
+		if(strcmp(entry2.get_field(), entry2z.get_field()))
+			return die_("bad value");
+		printf("OK\n");
+	}
+
+	printf("testing Entry::Entry(const char *field_name, const char *field_value, uint32_t field_value_length)... ");
+	FLAC::Metadata::VorbisComment::Entry entry3("name3", "value3", strlen("value3"));
+	if(!entry3.is_valid())
+		return die_("!is_valid()");
+	printf("OK\n");
+
+	{
+		printf("testing Entry::Entry(const char *field_name, const char *field_value)... ");
+		FLAC::Metadata::VorbisComment::Entry entry3z("name3", "value3");
+		if(!entry3z.is_valid())
+			return die_("!is_valid()");
+		if(strcmp(entry3.get_field(), entry3z.get_field()))
+			return die_("bad value");
+		printf("OK\n");
+	}
+
+	printf("testing Entry::Entry(const Entry &entry)... ");
+	{
+		FLAC::Metadata::VorbisComment::Entry entry2copy(entry2);
+		if(!entry2copy.is_valid())
+			return die_("!is_valid()");
+		printf("OK\n");
+
+		printf("testing Entry::~Entry()... ");
+	}
+	printf("OK\n");
+
+	printf("testing Entry::operator=(const Entry &entry)... ");
+	FLAC::Metadata::VorbisComment::Entry entry1 = entry2;
+	if(!entry2.is_valid())
+		return die_("!is_valid()");
+	printf("OK\n");
+
+	printf("testing Entry::get_field_length()... ");
+	if(entry1.get_field_length() != strlen("name2=value2"))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::get_field_name_length()... ");
+	if(entry1.get_field_name_length() != strlen("name2"))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::get_field_value_length()... ");
+	if(entry1.get_field_value_length() != strlen("value2"))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::get_entry()... ");
+	{
+		::FLAC__StreamMetadata_VorbisComment_Entry entry = entry1.get_entry();
+		if(entry.length != strlen("name2=value2"))
+			return die_("entry length mismatch");
+		if(0 != memcmp(entry.entry, "name2=value2", entry.length))
+			return die_("entry value mismatch");
+	}
+	printf("OK\n");
+
+	printf("testing Entry::get_field()... ");
+	if(0 != memcmp(entry1.get_field(), "name2=value2", strlen("name2=value2")))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::get_field_name()... ");
+	if(0 != memcmp(entry1.get_field_name(), "name2", strlen("name2")))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::get_field_value()... ");
+	if(0 != memcmp(entry1.get_field_value(), "value2", strlen("value2")))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::set_field_name()... ");
+	if(!entry1.set_field_name("name1"))
+		return die_("returned false");
+	if(0 != memcmp(entry1.get_field_name(), "name1", strlen("name1")))
+		return die_("value mismatch");
+	if(0 != memcmp(entry1.get_field(), "name1=value2", strlen("name1=value2")))
+		return die_("entry mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::set_field_value(const char *field_value, uint32_t field_value_length)... ");
+	if(!entry1.set_field_value("value1", strlen("value1")))
+		return die_("returned false");
+	if(0 != memcmp(entry1.get_field_value(), "value1", strlen("value1")))
+		return die_("value mismatch");
+	if(0 != memcmp(entry1.get_field(), "name1=value1", strlen("name1=value1")))
+		return die_("entry mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::set_field_value(const char *field_value)... ");
+	if(!entry1.set_field_value("value1"))
+		return die_("returned false");
+	if(0 != memcmp(entry1.get_field_value(), "value1", strlen("value1")))
+		return die_("value mismatch");
+	if(0 != memcmp(entry1.get_field(), "name1=value1", strlen("name1=value1")))
+		return die_("entry mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::set_field(const char *field, uint32_t field_length)... ");
+	if(!entry1.set_field("name0=value0", strlen("name0=value0")))
+		return die_("returned false");
+	if(0 != memcmp(entry1.get_field_name(), "name0", strlen("name0")))
+		return die_("value mismatch");
+	if(0 != memcmp(entry1.get_field_value(), "value0", strlen("value0")))
+		return die_("value mismatch");
+	if(0 != memcmp(entry1.get_field(), "name0=value0", strlen("name0=value0")))
+		return die_("entry mismatch");
+	printf("OK\n");
+
+	printf("testing Entry::set_field(const char *field)... ");
+	if(!entry1.set_field("name0=value0"))
+		return die_("returned false");
+	if(0 != memcmp(entry1.get_field_name(), "name0", strlen("name0")))
+		return die_("value mismatch");
+	if(0 != memcmp(entry1.get_field_value(), "value0", strlen("value0")))
+		return die_("value mismatch");
+	if(0 != memcmp(entry1.get_field(), "name0=value0", strlen("name0=value0")))
+		return die_("entry mismatch");
+	printf("OK\n");
+
+	printf("PASSED\n\n");
+
+
+	printf("testing class FLAC::Metadata::VorbisComment\n");
+
+	printf("testing VorbisComment::VorbisComment()... ");
+	FLAC::Metadata::VorbisComment block;
+	if(!block.is_valid())
+		return die_("!block.is_valid()");
+	expected_length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + strlen(::FLAC__VENDOR_STRING) + FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8);
+	if(block.get_length() != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing VorbisComment::VorbisComment(const VorbisComment &)... +\n");
+	printf("        VorbisComment::operator!=(const VorbisComment &)... ");
+	{
+		FLAC::Metadata::VorbisComment blockcopy(block);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != block)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+
+		printf("testing VorbisComment::~VorbisComment()... ");
+	}
+	printf("OK\n");
+
+	printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::VorbisComment blockcopy(vorbiscomment_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != vorbiscomment_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != vorbiscomment_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != vorbiscomment_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&vorbiscomment_);
+		FLAC::Metadata::VorbisComment blockcopy(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != vorbiscomment_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::VorbisComment blockcopy;
+		blockcopy.assign(&vorbiscomment_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != vorbiscomment_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&vorbiscomment_);
+		FLAC::Metadata::VorbisComment blockcopy;
+		blockcopy.assign(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != vorbiscomment_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::operator=(const VorbisComment &)... +\n");
+	printf("        VorbisComment::operator==(const VorbisComment &)... ");
+	{
+		FLAC::Metadata::VorbisComment blockcopy = block;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == block))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::operator=(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        VorbisComment::operator==(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::VorbisComment blockcopy = vorbiscomment_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == vorbiscomment_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::operator=(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        VorbisComment::operator==(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::VorbisComment blockcopy = &vorbiscomment_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == vorbiscomment_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing VorbisComment::get_num_comments()... ");
+	if(block.get_num_comments() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing VorbisComment::set_vendor_string()... ");
+	if(!block.set_vendor_string((const FLAC__byte *)"mame0"))
+		return die_("returned false");
+	printf("OK\n");
+	vorbiscomment_.data.vorbis_comment.vendor_string.entry[0] = 'm';
+
+	printf("testing VorbisComment::get_vendor_string()... ");
+	if(strlen((const char *)block.get_vendor_string()) != vorbiscomment_.data.vorbis_comment.vendor_string.length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_vendor_string(), vorbiscomment_.data.vorbis_comment.vendor_string.entry, vorbiscomment_.data.vorbis_comment.vendor_string.length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing VorbisComment::append_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.append_comment(entry3))
+		return die_("returned false");
+	if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing VorbisComment::append_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.append_comment(entry2))
+		return die_("returned false");
+	if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing VorbisComment::delete_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.delete_comment(0))
+		return die_("returned false");
+	if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+		return die_("length[0] mismatch");
+	if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+		return die_("value[0] mismatch");
+	printf("OK\n");
+
+	printf("testing VorbisComment::delete_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.delete_comment(0))
+		return die_("returned false");
+	if(block.get_num_comments() != 0)
+		return die_("block mismatch, expected num_comments = 0");
+	printf("OK\n");
+
+	printf("testing VorbisComment::insert_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.insert_comment(0, entry3))
+		return die_("returned false");
+	if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing VorbisComment::insert_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.insert_comment(0, entry3))
+		return die_("returned false");
+	if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing VorbisComment::insert_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.insert_comment(1, entry2))
+		return die_("returned false");
+	if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing VorbisComment::set_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.set_comment(0, entry2))
+		return die_("returned false");
+	if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing VorbisComment::delete_comment()... +\n");
+	printf("        VorbisComment::get_comment()... ");
+	if(!block.delete_comment(0))
+		return die_("returned false");
+	if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+		return die_("length[0] mismatch");
+	if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+		return die_("value[0] mismatch");
+	if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+		return die_("length[1] mismatch");
+	if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+		return die_("value[0] mismatch");
+	printf("OK\n");
+
+	printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+	FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+	if(0 == clone_)
+		return die_("returned NULL");
+	if(0 == dynamic_cast<FLAC::Metadata::VorbisComment *>(clone_))
+		return die_("downcast is NULL");
+	if(*dynamic_cast<FLAC::Metadata::VorbisComment *>(clone_) != block)
+		return die_("clone is not identical");
+	printf("OK\n");
+	printf("testing VorbisComment::~VorbisComment()... ");
+	delete clone_;
+	printf("OK\n");
+
+
+	printf("PASSED\n\n");
+	return true;
+}
+
+bool test_metadata_object_cuesheet()
+{
+	uint32_t expected_length;
+
+	printf("testing class FLAC::Metadata::CueSheet::Track\n");
+
+	printf("testing Track::Track()... ");
+	FLAC::Metadata::CueSheet::Track track0;
+	if(!track0.is_valid())
+		return die_("!is_valid()");
+	printf("OK\n");
+
+	{
+		printf("testing Track::get_track()... ");
+		const ::FLAC__StreamMetadata_CueSheet_Track *trackp = track0.get_track();
+		if(0 == trackp)
+			return die_("returned pointer is NULL");
+		printf("OK\n");
+
+		printf("testing Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track*)... ");
+		FLAC::Metadata::CueSheet::Track track2(trackp);
+		if(!track2.is_valid())
+			return die_("!is_valid()");
+		if(!track_is_equal_(track2.get_track(), trackp))
+			return die_("copy is not equal");
+		printf("OK\n");
+
+		printf("testing Track::~Track()... ");
+	}
+	printf("OK\n");
+
+	printf("testing Track::Track(const Track &track)... ");
+	{
+		FLAC::Metadata::CueSheet::Track track0copy(track0);
+		if(!track0copy.is_valid())
+			return die_("!is_valid()");
+		if(!track_is_equal_(track0copy.get_track(), track0.get_track()))
+			return die_("copy is not equal");
+		printf("OK\n");
+
+		printf("testing Track::~Track()... ");
+	}
+	printf("OK\n");
+
+	printf("testing Track::operator=(const Track &track)... ");
+	FLAC::Metadata::CueSheet::Track track1 = track0;
+	if(!track0.is_valid())
+		return die_("!is_valid()");
+	if(!track_is_equal_(track1.get_track(), track0.get_track()))
+		return die_("copy is not equal");
+	printf("OK\n");
+
+	printf("testing Track::get_offset()... ");
+	if(track1.get_offset() != 0)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::get_number()... ");
+	if(track1.get_number() != 0)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::get_isrc()... ");
+	if(0 != memcmp(track1.get_isrc(), "\0\0\0\0\0\0\0\0\0\0\0\0\0", 13))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::get_type()... ");
+	if(track1.get_type() != 0)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::get_pre_emphasis()... ");
+	if(track1.get_pre_emphasis() != 0)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::get_num_indices()... ");
+	if(track1.get_num_indices() != 0)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::set_offset()... ");
+	track1.set_offset(588);
+	if(track1.get_offset() != 588)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::set_number()... ");
+	track1.set_number(1);
+	if(track1.get_number() != 1)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::set_isrc()... ");
+	track1.set_isrc("ABCDE1234567");
+	if(0 != memcmp(track1.get_isrc(), "ABCDE1234567", 13))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::set_type()... ");
+	track1.set_type(1);
+	if(track1.get_type() != 1)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Track::set_pre_emphasis()... ");
+	track1.set_pre_emphasis(1);
+	if(track1.get_pre_emphasis() != 1)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("PASSED\n\n");
+
+	printf("testing class FLAC::Metadata::CueSheet\n");
+
+	printf("testing CueSheet::CueSheet()... ");
+	FLAC::Metadata::CueSheet block;
+	if(!block.is_valid())
+		return die_("!block.is_valid()");
+	expected_length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+	if(block.get_length() != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing CueSheet::CueSheet(const CueSheet &)... +\n");
+	printf("        CueSheet::operator!=(const CueSheet &)... ");
+	{
+		FLAC::Metadata::CueSheet blockcopy(block);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != block)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+
+		printf("testing CueSheet::~CueSheet()... ");
+	}
+	printf("OK\n");
+
+	printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::CueSheet blockcopy(cuesheet_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != cuesheet_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::CueSheet blockcopy(&cuesheet_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != cuesheet_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::CueSheet blockcopy(&cuesheet_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != cuesheet_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&cuesheet_);
+		FLAC::Metadata::CueSheet blockcopy(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != cuesheet_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::CueSheet blockcopy;
+		blockcopy.assign(&cuesheet_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != cuesheet_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&cuesheet_);
+		FLAC::Metadata::CueSheet blockcopy;
+		blockcopy.assign(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != cuesheet_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::operator=(const CueSheet &)... +\n");
+	printf("        CueSheet::operator==(const CueSheet &)... ");
+	{
+		FLAC::Metadata::CueSheet blockcopy = block;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == block))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::operator=(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        CueSheet::operator==(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::CueSheet blockcopy = cuesheet_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == cuesheet_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::operator=(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        CueSheet::operator==(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::CueSheet blockcopy = &cuesheet_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == cuesheet_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing CueSheet::get_media_catalog_number()... ");
+	if(0 != strcmp(block.get_media_catalog_number(), ""))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing CueSheet::get_lead_in()... ");
+	if(block.get_lead_in() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing CueSheet::get_is_cd()... ");
+	if(block.get_is_cd())
+		return die_("value mismatch, expected false");
+	printf("OK\n");
+
+	printf("testing CueSheet::get_num_tracks()... ");
+	if(block.get_num_tracks() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing CueSheet::set_media_catalog_number()... ");
+	{
+		char mcn[129];
+		memset(mcn, 0, sizeof(mcn));
+		safe_strncpy(mcn, "1234567890123", sizeof(mcn));
+		block.set_media_catalog_number(mcn);
+		if(0 != memcmp(block.get_media_catalog_number(), mcn, sizeof(mcn)))
+			return die_("value mismatch");
+	}
+	printf("OK\n");
+
+	printf("testing CueSheet::set_lead_in()... ");
+	block.set_lead_in(588);
+	if(block.get_lead_in() != 588)
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing CueSheet::set_is_cd()... ");
+	block.set_is_cd(true);
+	if(!block.get_is_cd())
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing CueSheet::insert_track()... +\n");
+	printf("        CueSheet::get_track()... ");
+	if(!block.insert_track(0, track0))
+		return die_("returned false");
+	if(!track_is_equal_(block.get_track(0).get_track(), track0.get_track()))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing CueSheet::insert_track()... +\n");
+	printf("        CueSheet::get_track()... ");
+	if(!block.insert_track(1, track1))
+		return die_("returned false");
+	if(!track_is_equal_(block.get_track(1).get_track(), track1.get_track()))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	::FLAC__StreamMetadata_CueSheet_Index index0;
+	index0.offset = 588*4;
+	index0.number = 1;
+
+	printf("testing CueSheet::insert_index(0)... +\n");
+	printf("        CueSheet::get_track()... +\n");
+	printf("        CueSheet::Track::get_index()... ");
+	if(!block.insert_index(0, 0, index0))
+		return die_("returned false");
+	if(!index_is_equal_(block.get_track(0).get_index(0), index0))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	index0.offset = 588*5;
+	printf("testing CueSheet::Track::set_index()... ");
+	{
+		FLAC::Metadata::CueSheet::Track track_ = block.get_track(0);
+		track_.set_index(0, index0);
+		if(!index_is_equal_(track_.get_index(0), index0))
+			return die_("value mismatch");
+	}
+	printf("OK\n");
+
+	index0.offset = 588*6;
+	printf("testing CueSheet::set_index()... ");
+	block.set_index(0, 0, index0);
+	if(!index_is_equal_(block.get_track(0).get_index(0), index0))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing CueSheet::delete_index()... ");
+	if(!block.delete_index(0, 0))
+		return die_("returned false");
+	if(block.get_track(0).get_num_indices() != 0)
+		return die_("num_indices mismatch");
+	printf("OK\n");
+
+
+	printf("testing CueSheet::set_track()... +\n");
+	printf("        CueSheet::get_track()... ");
+	if(!block.set_track(0, track1))
+		return die_("returned false");
+	if(!track_is_equal_(block.get_track(0).get_track(), track1.get_track()))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing CueSheet::delete_track()... ");
+	if(!block.delete_track(0))
+		return die_("returned false");
+	if(block.get_num_tracks() != 1)
+		return die_("num_tracks mismatch");
+	printf("OK\n");
+
+	printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+	FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+	if(0 == clone_)
+		return die_("returned NULL");
+	if(0 == dynamic_cast<FLAC::Metadata::CueSheet *>(clone_))
+		return die_("downcast is NULL");
+	if(*dynamic_cast<FLAC::Metadata::CueSheet *>(clone_) != block)
+		return die_("clone is not identical");
+	printf("OK\n");
+	printf("testing CueSheet::~CueSheet()... ");
+	delete clone_;
+	printf("OK\n");
+
+	printf("PASSED\n\n");
+	return true;
+}
+
+bool test_metadata_object_picture()
+{
+	uint32_t expected_length;
+
+	printf("testing class FLAC::Metadata::Picture\n");
+
+	printf("testing Picture::Picture()... ");
+	FLAC::Metadata::Picture block;
+	if(!block.is_valid())
+		return die_("!block.is_valid()");
+	expected_length = (
+		FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+		FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN +
+		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
+	) / 8;
+	if(block.get_length() != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing Picture::Picture(const Picture &)... +\n");
+	printf("        Picture::operator!=(const Picture &)... ");
+	{
+		FLAC::Metadata::Picture blockcopy(block);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != block)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+
+		printf("testing Picture::~Picture()... ");
+	}
+	printf("OK\n");
+
+	printf("testing Picture::Picture(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::Picture blockcopy(picture_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::Picture(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Picture blockcopy(&picture_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Picture blockcopy(&picture_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_);
+		FLAC::Metadata::Picture blockcopy(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Picture blockcopy;
+		blockcopy.assign(&picture_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_);
+		FLAC::Metadata::Picture blockcopy;
+		blockcopy.assign(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::operator=(const Picture &)... +\n");
+	printf("        Picture::operator==(const Picture &)... ");
+	{
+		FLAC::Metadata::Picture blockcopy = block;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == block))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::operator=(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        Picture::operator==(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::Picture blockcopy = picture_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == picture_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::operator=(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        Picture::operator==(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Picture blockcopy = &picture_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == picture_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::get_type()... ");
+	if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER)
+		return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER");
+	printf("OK\n");
+
+	printf("testing Picture::set_type()... +\n");
+	printf("        Picture::get_type()... ");
+	block.set_type(::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA);
+	if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA)
+		return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA");
+	printf("OK\n");
+
+	printf("testing Picture::set_mime_type()... ");
+	if(!block.set_mime_type("qmage/jpeg"))
+		return die_("returned false");
+	printf("OK\n");
+	picture_.data.picture.mime_type[0] = 'q';
+
+	printf("testing Picture::get_mime_type()... ");
+	if(0 != strcmp(block.get_mime_type(), picture_.data.picture.mime_type))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Picture::set_description()... ");
+	if(!block.set_description((const FLAC__byte*)"qesc"))
+		return die_("returned false");
+	printf("OK\n");
+	picture_.data.picture.description[0] = 'q';
+
+	printf("testing Picture::get_description()... ");
+	if(0 != strcmp((const char *)block.get_description(), (const char *)picture_.data.picture.description))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Picture::get_width()... ");
+	if(block.get_width() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_width()... +\n");
+	printf("        Picture::get_width()... ");
+	block.set_width(400);
+	if(block.get_width() != 400)
+		return die_("value mismatch, expected 400");
+	printf("OK\n");
+
+	printf("testing Picture::get_height()... ");
+	if(block.get_height() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_height()... +\n");
+	printf("        Picture::get_height()... ");
+	block.set_height(200);
+	if(block.get_height() != 200)
+		return die_("value mismatch, expected 200");
+	printf("OK\n");
+
+	printf("testing Picture::get_depth()... ");
+	if(block.get_depth() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_depth()... +\n");
+	printf("        Picture::get_depth()... ");
+	block.set_depth(16);
+	if(block.get_depth() != 16)
+		return die_("value mismatch, expected 16");
+	printf("OK\n");
+
+	printf("testing Picture::get_colors()... ");
+	if(block.get_colors() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_colors()... +\n");
+	printf("        Picture::get_colors()... ");
+	block.set_colors(1u>16);
+	if(block.get_colors() != (1u>16))
+		return die_("value mismatch, expected 2^16");
+	printf("OK\n");
+
+	printf("testing Picture::get_data_length()... ");
+	if(block.get_data_length() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_data()... ");
+	if(!block.set_data((const FLAC__byte*)"qOMEJPEGDATA", strlen("qOMEJPEGDATA")))
+		return die_("returned false");
+	printf("OK\n");
+	picture_.data.picture.data[0] = 'q';
+
+	printf("testing Picture::get_data()... ");
+	if(block.get_data_length() != picture_.data.picture.data_length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_data(), picture_.data.picture.data, picture_.data.picture.data_length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+	FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+	if(0 == clone_)
+		return die_("returned NULL");
+	if(0 == dynamic_cast<FLAC::Metadata::Picture *>(clone_))
+		return die_("downcast is NULL");
+	if(*dynamic_cast<FLAC::Metadata::Picture *>(clone_) != block)
+		return die_("clone is not identical");
+	printf("OK\n");
+	printf("testing Picture::~Picture()... ");
+	delete clone_;
+	printf("OK\n");
+
+
+	printf("PASSED\n\n");
+	return true;
+}
+
+bool test_metadata_object()
+{
+	printf("\n+++ libFLAC++ unit test: metadata objects\n\n");
+
+	init_metadata_blocks_();
+
+	if(!test_metadata_object_streaminfo())
+		return false;
+
+	if(!test_metadata_object_padding())
+		return false;
+
+	if(!test_metadata_object_application())
+		return false;
+
+	if(!test_metadata_object_seektable())
+		return false;
+
+	if(!test_metadata_object_vorbiscomment())
+		return false;
+
+	if(!test_metadata_object_cuesheet())
+		return false;
+
+	if(!test_metadata_object_picture())
+		return false;
+
+	free_metadata_blocks_();
+
+	return true;
+}
diff --git a/src/test_libFLAC++/test_libFLAC++.vcproj b/src/test_libFLAC++/test_libFLAC++.vcproj
new file mode 100644
index 0000000..b9152c5
--- /dev/null
+++ b/src/test_libFLAC++/test_libFLAC++.vcproj
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="test_libFLAC++"

+	ProjectGUID="{4cefbc8d-c215-11db-8314-0800200c9a66}"

+	RootNamespace="test_libFLAC++"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\decoders.h"

+				>

+			</File>

+			<File

+				RelativePath=".\encoders.h"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\decoders.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\encoders.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\main.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_manip.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_object.cpp"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/test_libFLAC++/test_libFLAC++.vcxproj b/src/test_libFLAC++/test_libFLAC++.vcxproj
new file mode 100644
index 0000000..c356e62
--- /dev/null
+++ b/src/test_libFLAC++/test_libFLAC++.vcxproj
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc8d-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>test_libFLAC++</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="decoders.h" />

+    <ClInclude Include="encoders.h" />

+    <ClInclude Include="metadata.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="decoders.cpp" />

+    <ClCompile Include="encoders.cpp" />

+    <ClCompile Include="main.cpp" />

+    <ClCompile Include="metadata.cpp" />

+    <ClCompile Include="metadata_manip.cpp" />

+    <ClCompile Include="metadata_object.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC++\libFLAC++_static.vcxproj">

+      <Project>{4cefbc86-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+    </ProjectReference>

+    <ProjectReference Include="..\share\grabbag\grabbag_static.vcxproj">

+      <Project>{4cefbc81-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\test_libs_common\test_libs_common_static.vcxproj">

+      <Project>{4cefbc8e-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_libFLAC++/test_libFLAC++.vcxproj.filters b/src/test_libFLAC++/test_libFLAC++.vcxproj.filters
new file mode 100644
index 0000000..f11af8d
--- /dev/null
+++ b/src/test_libFLAC++/test_libFLAC++.vcxproj.filters
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="decoders.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="encoders.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="metadata.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="decoders.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="encoders.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="main.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_manip.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_object.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_libFLAC/CMakeLists.txt b/src/test_libFLAC/CMakeLists.txt
new file mode 100644
index 0000000..36a5820
--- /dev/null
+++ b/src/test_libFLAC/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_executable(test_libFLAC
+    bitreader.c
+    bitwriter.c
+    crc.c
+    decoders.c
+    encoders.c
+    endswap.c
+    format.c
+    main.c
+    metadata.c
+    metadata_manip.c
+    metadata_object.c
+    md5.c
+    "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/bitreader.c"
+    "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/bitwriter.c"
+    "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/crc.c"
+    "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/md5.c"
+    $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+    $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+
+target_compile_definitions(test_libFLAC PRIVATE
+    $<$<BOOL:${ENABLE_64_BIT_WORDS}>:ENABLE_64_BIT_WORDS>)
+target_include_directories(test_libFLAC PRIVATE
+    "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/include")
+target_link_libraries(test_libFLAC FLAC grabbag test_libs_common)
diff --git a/src/test_libFLAC/Makefile.am b/src/test_libFLAC/Makefile.am
new file mode 100644
index 0000000..1a361a1
--- /dev/null
+++ b/src/test_libFLAC/Makefile.am
@@ -0,0 +1,66 @@
+#  test_libFLAC - Unit tester for libFLAC
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2018  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	test_libFLAC.vcproj \
+	test_libFLAC.vcxproj \
+	test_libFLAC.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src/libFLAC/include
+
+check_PROGRAMS = test_libFLAC
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+test_libFLAC_LDADD = \
+	$(top_builddir)/src/share/grabbag/libgrabbag.la \
+	$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+	$(top_builddir)/src/test_libs_common/libtest_libs_common.la \
+	$(top_builddir)/src/libFLAC/libFLAC-static.la \
+	$(win_utf8_lib) \
+	@OGG_LIBS@ \
+	-lm
+
+test_libFLAC_SOURCES = \
+	bitreader.c \
+	bitwriter.c \
+	crc.c \
+	decoders.c \
+	encoders.c \
+	endswap.c \
+	format.c \
+	main.c \
+	metadata.c \
+	metadata_manip.c \
+	metadata_object.c \
+	md5.c \
+	bitreader.h \
+	bitwriter.h \
+	crc.h \
+	decoders.h \
+	encoders.h \
+	endswap.h \
+	format.h \
+	metadata.h \
+	md5.h
+
+CLEANFILES = test_libFLAC.exe
diff --git a/src/test_libFLAC/Makefile.lite b/src/test_libFLAC/Makefile.lite
new file mode 100644
index 0000000..a9c9ac1
--- /dev/null
+++ b/src/test_libFLAC/Makefile.lite
@@ -0,0 +1,58 @@
+#  test_libFLAC - Unit tester for libFLAC
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2018  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = test_libFLAC
+
+INCLUDES = -I../libFLAC/include -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libtest_libs_common.a $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+ifeq ($(findstring Windows,$(OS)),Windows)
+    LIBS = -lgrabbag -lreplaygain_analysis -ltest_libs_common -lFLAC -lwin_utf8_io $(OGG_LIBS) -lm
+else
+    LIBS = -lgrabbag -lreplaygain_analysis -ltest_libs_common -lFLAC $(OGG_LIBS) -lm
+endif
+endif
+
+SRCS_C = \
+	bitreader.c \
+	bitwriter.c \
+	crc.c \
+	decoders.c \
+	encoders.c \
+	endswap.c \
+	format.c \
+	main.c \
+	md5.c \
+	metadata.c \
+	metadata_manip.c \
+	metadata_object.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_libFLAC/bitreader.c b/src/test_libFLAC/bitreader.c
new file mode 100644
index 0000000..63eae69
--- /dev/null
+++ b/src/test_libFLAC/bitreader.c
@@ -0,0 +1,322 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/bitreader.h" /* from the libFLAC private include area */
+#include "bitreader.h"
+#include <stdio.h>
+#include <string.h> /* for memcpy() */
+
+/*
+ * WATCHOUT!  Since FLAC__BitReader is a private structure, we use a copy of
+ * the definition here to get at the internals.  Make sure this is kept up
+ * to date with what is in ../libFLAC/bitreader.c
+ */
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 brword;
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+
+#else
+
+typedef FLAC__uint64 brword;
+#define FLAC__BYTES_PER_WORD 8
+#define FLAC__BITS_PER_WORD 64
+
+#endif
+
+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 */
+	brword *buffer;
+	uint32_t capacity; /* in words */
+	uint32_t words; /* # of completed words in buffer */
+	uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */
+	uint32_t consumed_words; /* #words ... */
+	uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+	uint32_t read_crc16; /* the running frame CRC */
+	uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */
+	uint32_t 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 FLAC__bool read_callback(FLAC__byte buffer[], size_t *bytes, void *data);
+
+FLAC__bool test_bitreader(void)
+{
+	FLAC__BitReader *br;
+	FLAC__bool ok;
+	uint32_t i;
+	uint32_t words, bits; /* what we think br->consumed_words and br->consumed_bits should be */
+
+	FLAC__uint16	 crc,expected_crcs[4] = { 0x5e4c, 0x7f6b, 0x2272, 0x42bf };
+	FLAC__byte	 data[32];
+
+	FLAC__uint32	 val_uint32;
+	FLAC__uint64	 val_uint64;
+
+	for (i = 0; i < 32; i++)
+		data[i] = i * 8 + 7;
+
+	printf("\n+++ libFLAC unit test: bitreader\n\n");
+
+	/*
+	 * test new -> delete
+	 */
+	printf("testing new... ");
+	br = FLAC__bitreader_new();
+	if(0 == br) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing delete... ");
+	FLAC__bitreader_delete(br);
+	printf("OK\n");
+
+	/*
+	 * test new -> init -> delete
+	 */
+	printf("testing new... ");
+	br = FLAC__bitreader_new();
+	if(0 == br) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing init... ");
+	if(!FLAC__bitreader_init(br, read_callback, data)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing delete... ");
+	FLAC__bitreader_delete(br);
+	printf("OK\n");
+
+	/*
+	 * test new -> init -> clear -> delete
+	 */
+	printf("testing new... ");
+	br = FLAC__bitreader_new();
+	if(0 == br) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing init... ");
+	if(!FLAC__bitreader_init(br, read_callback, data)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing clear... ");
+	if(!FLAC__bitreader_clear(br)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing delete... ");
+	FLAC__bitreader_delete(br);
+	printf("OK\n");
+
+	/*
+	 * test normal usage
+	 */
+	printf("testing new... ");
+	br = FLAC__bitreader_new();
+	if(0 == br) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing init... ");
+	if(!FLAC__bitreader_init(br, read_callback, data)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing clear... ");
+	if(!FLAC__bitreader_clear(br)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	words = bits = 0;
+
+	printf("capacity = %u\n", br->capacity);
+
+	printf("testing raw reads... ");
+	ok =
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 10) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 4) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 4) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) &&
+		FLAC__bitreader_read_raw_uint64(br, &val_uint64, 64) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 12)
+	;
+	if(!ok) {
+		printf("FAILED\n");
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	/* we read 152 bits (=19 bytes) from the bitreader */
+	words = 152 / FLAC__BITS_PER_WORD;
+	bits = 152 - words*FLAC__BITS_PER_WORD;
+
+	if(br->consumed_words != words) {
+		printf("FAILED word count %u != %u\n", br->consumed_words, words);
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	if(br->consumed_bits != bits) {
+		printf("FAILED bit count %u != %u\n", br->consumed_bits, bits);
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	crc = FLAC__bitreader_get_read_crc16(br);
+	if(crc != expected_crcs[0]) {
+		printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[0]);
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	printf("OK\n");
+	FLAC__bitreader_dump(br, stdout);
+
+	printf("testing CRC reset... ");
+	FLAC__bitreader_clear(br);
+	FLAC__bitreader_reset_read_crc16(br, 0xFFFF);
+	crc = FLAC__bitreader_get_read_crc16(br);
+	if(crc != 0xFFFF) {
+		printf("FAILED reported CRC 0x%04x does not match expected 0xFFFF\n", crc);
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	FLAC__bitreader_reset_read_crc16(br, 0);
+	crc = FLAC__bitreader_get_read_crc16(br);
+	if(crc != 0) {
+		printf("FAILED reported CRC 0x%04x does not match expected 0x0000\n", crc);
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	FLAC__bitreader_read_raw_uint32(br, &val_uint32, 16);
+	FLAC__bitreader_reset_read_crc16(br, 0);
+	FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32);
+	crc = FLAC__bitreader_get_read_crc16(br);
+	if(crc != expected_crcs[1]) {
+		printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[1]);
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing unaligned < 32 bit reads... ");
+	FLAC__bitreader_clear(br);
+	FLAC__bitreader_skip_bits_no_crc(br, 8);
+	FLAC__bitreader_reset_read_crc16(br, 0);
+	ok =
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8)
+	;
+	if(!ok) {
+		printf("FAILED\n");
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	crc = FLAC__bitreader_get_read_crc16(br);
+	if(crc != expected_crcs[2]) {
+		printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[2]);
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	printf("OK\n");
+	FLAC__bitreader_dump(br, stdout);
+
+	printf("testing unaligned < 64 bit reads... ");
+	FLAC__bitreader_clear(br);
+	FLAC__bitreader_skip_bits_no_crc(br, 8);
+	FLAC__bitreader_reset_read_crc16(br, 0);
+	ok =
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) &&
+		FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32)
+	;
+	if(!ok) {
+		printf("FAILED\n");
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	crc = FLAC__bitreader_get_read_crc16(br);
+	if(crc != expected_crcs[3]) {
+		printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[3]);
+		FLAC__bitreader_dump(br, stdout);
+		return false;
+	}
+	printf("OK\n");
+	FLAC__bitreader_dump(br, stdout);
+
+	printf("testing free... ");
+	FLAC__bitreader_free(br);
+	printf("OK\n");
+
+	printf("testing delete... ");
+	FLAC__bitreader_delete(br);
+	printf("OK\n");
+
+	printf("\nPASSED!\n");
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static FLAC__bool read_callback(FLAC__byte buffer[], size_t *bytes, void *data)
+{
+	if (*bytes > 32)
+		*bytes = 32;
+
+	memcpy(buffer, data, *bytes);
+
+	return true;
+}
diff --git a/src/test_libFLAC/bitreader.h b/src/test_libFLAC/bitreader.h
new file mode 100644
index 0000000..b4e02c0
--- /dev/null
+++ b/src/test_libFLAC/bitreader.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_BITREADER_H
+#define FLAC__TEST_LIBFLAC_BITREADER_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_bitreader(void);
+
+#endif
diff --git a/src/test_libFLAC/bitwriter.c b/src/test_libFLAC/bitwriter.c
new file mode 100644
index 0000000..b779ae5
--- /dev/null
+++ b/src/test_libFLAC/bitwriter.c
@@ -0,0 +1,665 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/bitwriter.h" /* from the libFLAC private include area */
+#include "bitwriter.h"
+#include <stdio.h>
+#include <string.h> /* for memcmp() */
+
+/*
+ * WATCHOUT!  Since FLAC__BitWriter is a private structure, we use a copy of
+ * the definition here to get at the internals.  Make sure this is kept up
+ * to date with what is in ../libFLAC/bitwriter.c
+ */
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 bwword;
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+#define PRI_BWWORD "08x"
+
+#else
+
+typedef FLAC__uint64 bwword;
+#define FLAC__BYTES_PER_WORD 8
+#define FLAC__BITS_PER_WORD 64
+#define PRI_BWWORD "016" PRIx64
+
+#endif
+
+struct FLAC__BitWriter {
+	bwword *buffer;
+	bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */
+	uint32_t capacity; /* capacity of buffer in words */
+	uint32_t words; /* # of complete words in buffer */
+	uint32_t bits; /* # of used bits in accum */
+};
+
+#define WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD)
+#define TOTAL_BITS(bw) (WORDS_TO_BITS((bw)->words) + (bw)->bits)
+
+
+FLAC__bool test_bitwriter(void)
+{
+	FLAC__BitWriter *bw;
+	FLAC__bool ok;
+	uint32_t i, j;
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	static bwword test_pattern1[5] = { 0xaaf0aabe, 0xaaaaaaa8, 0x300aaaaa, 0xaaadeadb, 0x00eeface };
+#else
+	static bwword test_pattern1[5] = { 0xbeaaf0aa, 0xa8aaaaaa, 0xaaaa0a30, 0xdbeaadaa, 0x00eeface };
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+#if WORDS_BIGENDIAN
+	static bwword test_pattern1[3] = { FLAC__U64L(0xaaf0aabeaaaaaaa8), FLAC__U64L(0x300aaaaaaaadeadb), FLAC__U64L(0x0000000000eeface) };
+#else
+	static bwword test_pattern1[3] = { FLAC__U64L(0xa8aaaaaabeaaf0aa), FLAC__U64L(0xdbeaadaaaaaa0a30), FLAC__U64L(0x0000000000eeface) };
+#endif
+#else
+#error FLAC__BYTES_PER_WORD is neither 4 nor 8 -- not implemented
+#endif
+	uint32_t words, bits; /* what we think bw->words and bw->bits should be */
+
+	printf("\n+++ libFLAC unit test: bitwriter\n\n");
+
+	/*
+	 * test new -> delete
+	 */
+	printf("testing new... ");
+	bw = FLAC__bitwriter_new();
+	if(0 == bw) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing delete... ");
+	FLAC__bitwriter_delete(bw);
+	printf("OK\n");
+
+	/*
+	 * test new -> init -> delete
+	 */
+	printf("testing new... ");
+	bw = FLAC__bitwriter_new();
+	if(0 == bw) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing init... ");
+	if(!FLAC__bitwriter_init(bw)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing delete... ");
+	FLAC__bitwriter_delete(bw);
+	printf("OK\n");
+
+	/*
+	 * test new -> init -> clear -> delete
+	 */
+	printf("testing new... ");
+	bw = FLAC__bitwriter_new();
+	if(0 == bw) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing init... ");
+	if(!FLAC__bitwriter_init(bw)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing clear... ");
+	FLAC__bitwriter_clear(bw);
+	printf("OK\n");
+
+	printf("testing delete... ");
+	FLAC__bitwriter_delete(bw);
+	printf("OK\n");
+
+	/*
+	 * test normal usage
+	 */
+	printf("testing new... ");
+	bw = FLAC__bitwriter_new();
+	if(0 == bw) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing init... ");
+	if(!FLAC__bitwriter_init(bw)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing clear... ");
+	FLAC__bitwriter_clear(bw);
+	printf("OK\n");
+
+	words = bits = 0;
+
+	printf("capacity = %u\n", bw->capacity);
+
+	printf("testing zeroes, raw_uint32*... ");
+	ok =
+		FLAC__bitwriter_write_raw_uint32(bw, 0x1, 1) &&
+		FLAC__bitwriter_write_raw_uint32(bw, 0x1, 2) &&
+		FLAC__bitwriter_write_raw_uint32(bw, 0xa, 5) &&
+		FLAC__bitwriter_write_raw_uint32(bw, 0xf0, 8) &&
+		FLAC__bitwriter_write_raw_uint32(bw, 0x2aa, 10) &&
+		FLAC__bitwriter_write_raw_uint32(bw, 0xf, 4) &&
+		FLAC__bitwriter_write_raw_uint32(bw, 0xaaaaaaaa, 32) &&
+		FLAC__bitwriter_write_zeroes(bw, 4) &&
+		FLAC__bitwriter_write_raw_uint32(bw, 0x3, 2) &&
+		FLAC__bitwriter_write_zeroes(bw, 8) &&
+		FLAC__bitwriter_write_raw_uint64(bw, FLAC__U64L(0xaaaaaaaadeadbeef), 64) &&
+		FLAC__bitwriter_write_raw_uint32(bw, 0xace, 12)
+	;
+	if(!ok) {
+		printf("FAILED\n");
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	/* we wrote 152 bits (=19 bytes) to the bitwriter */
+	words = 152 / FLAC__BITS_PER_WORD;
+	bits = 152 - words*FLAC__BITS_PER_WORD;
+
+	if(bw->words != words) {
+		printf("FAILED word count %u != %u\n", bw->words, words);
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	if(bw->bits != bits) {
+		printf("FAILED bit count %u != %u\n", bw->bits, bits);
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	if(memcmp(bw->buffer, test_pattern1, sizeof(bwword)*words) != 0) {
+		printf("FAILED pattern match (buffer)\n");
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	if((bw->accum & 0x00ffffff) != test_pattern1[words]) {
+		printf("FAILED pattern match (bw->accum=%" PRI_BWWORD " != %" PRI_BWWORD ")\n", bw->accum&0x00ffffff, test_pattern1[words]);
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	printf("OK\n");
+	FLAC__bitwriter_dump(bw, stdout);
+
+	printf("testing raw_uint32 some more... ");
+	ok = FLAC__bitwriter_write_raw_uint32(bw, 0x3d, 6);
+	if(!ok) {
+		printf("FAILED\n");
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	bits += 6;
+	test_pattern1[words] <<= 6;
+	test_pattern1[words] |= 0x3d;
+	if(bw->words != words) {
+		printf("FAILED word count %u != %u\n", bw->words, words);
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	if(bw->bits != bits) {
+		printf("FAILED bit count %u != %u\n", bw->bits, bits);
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	if(memcmp(bw->buffer, test_pattern1, sizeof(bwword)*words) != 0) {
+		printf("FAILED pattern match (buffer)\n");
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	if((bw->accum & 0x3fffffff) != test_pattern1[words]) {
+		printf("FAILED pattern match (bw->accum=%" PRI_BWWORD " != %" PRI_BWWORD ")\n", bw->accum&0x3fffffff, test_pattern1[words]);
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	printf("OK\n");
+	FLAC__bitwriter_dump(bw, stdout);
+
+	printf("testing utf8_uint32(0x00000000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x00000000);
+	ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x0000007F)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x0000007F);
+	ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0x7F;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x00000080)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x00000080);
+	ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xC280;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x000007FF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x000007FF);
+	ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xDFBF;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x00000800)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x00000800);
+	ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xE0A080;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x0000FFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x0000FFFF);
+	ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xEFBFBF;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x00010000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x00010000);
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080;
+#else
+	ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF0908080;
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x001FFFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x001FFFFF);
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF;
+#else
+	ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF7BFBFBF;
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x00200000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x00200000);
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xF8888080 && (bw->accum & 0xff) == 0x80;
+#else
+	ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0x808088F8 && (bw->accum & 0xff) == 0x80;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xF888808080);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x03FFFFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x03FFFFFF);
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xFBBFBFBF && (bw->accum & 0xff) == 0xBF;
+#else
+	ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xBFBFBFFB && (bw->accum & 0xff) == 0xBF;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xFBBFBFBFBF);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x04000000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x04000000);
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFC848080 && (bw->accum & 0xffff) == 0x8080;
+#else
+	ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0x808084FC && (bw->accum & 0xffff) == 0x8080;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFC8480808080);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint32(0x7FFFFFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint32(bw, 0x7FFFFFFF);
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFDBFBFBF && (bw->accum & 0xffff) == 0xBFBF;
+#else
+	ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xBFBFBFFD && (bw->accum & 0xffff) == 0xBFBF;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFDBFBFBFBFBF);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000000000000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000000000));
+	ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x000000000000007F)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x000000000000007F));
+	ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0x7F;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000000000080)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000000080));
+	ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xC280;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x00000000000007FF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x00000000000007FF));
+	ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xDFBF;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000000000800)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000000800));
+	ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xE0A080;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x000000000000FFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x000000000000FFFF));
+	ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xEFBFBF;
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000000010000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000010000));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080;
+#else
+	ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF0908080;
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x00000000001FFFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x00000000001FFFFF));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF;
+#else
+	ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF7BFBFBF;
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000000200000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000200000));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xF8888080 && (bw->accum & 0xff) == 0x80;
+#else
+	ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0x808088F8 && (bw->accum & 0xff) == 0x80;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xF888808080);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000003FFFFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000003FFFFFF));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xFBBFBFBF && (bw->accum & 0xff) == 0xBF;
+#else
+	ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xBFBFBFFB && (bw->accum & 0xff) == 0xBF;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xFBBFBFBFBF);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000004000000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000004000000));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFC848080 && (bw->accum & 0xffff) == 0x8080;
+#else
+	ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0x808084FC && (bw->accum & 0xffff) == 0x8080;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFC8480808080);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x000000007FFFFFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x000000007FFFFFFF));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFDBFBFBF && (bw->accum & 0xffff) == 0xBFBF;
+#else
+	ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xBFBFBFFD && (bw->accum & 0xffff) == 0xBFBF;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFDBFBFBFBFBF);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000080000000)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000080000000));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xFE828080 && (bw->accum & 0xffffff) == 0x808080;
+#else
+	ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0x808082FE && (bw->accum & 0xffffff) == 0x808080;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 56 && (bw->accum & FLAC__U64L(0xffffffffffffff)) == FLAC__U64L(0xFE828080808080);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing utf8_uint64(0x0000000FFFFFFFFF)... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000FFFFFFFFF));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xFEBFBFBF && (bw->accum & 0xffffff) == 0xBFBFBF;
+#else
+	ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xBFBFBFFE && (bw->accum & 0xffffff) == 0xBFBFBF;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+	ok = TOTAL_BITS(bw) == 56 && (bw->accum & FLAC__U64L(0xffffffffffffff)) == FLAC__U64L(0xFEBFBFBFBFBFBF);
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+
+	printf("testing grow... ");
+	FLAC__bitwriter_clear(bw);
+	FLAC__bitwriter_write_raw_uint32(bw, 0x5, 4);
+	j = bw->capacity;
+	for(i = 0; i < j; i++)
+		FLAC__bitwriter_write_raw_uint32(bw, 0xaaaaaaaa, 32);
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == 0x5aaaaaaa && (bw->accum & 0xf) == 0xa;
+#else
+	ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == 0xaaaaaa5a && (bw->accum & 0xf) == 0xa;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+#if WORDS_BIGENDIAN
+	ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == FLAC__U64L(0x5aaaaaaaaaaaaaaa) && (bw->accum & 0xf) == 0xa;
+#else
+	ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == FLAC__U64L(0xaaaaaaaaaaaaaa5a) && (bw->accum & 0xf) == 0xa;
+#endif
+#endif
+	printf("%s\n", ok?"OK":"FAILED");
+	if(!ok) {
+		FLAC__bitwriter_dump(bw, stdout);
+		return false;
+	}
+	printf("capacity = %u\n", bw->capacity);
+
+	printf("testing free... ");
+	FLAC__bitwriter_free(bw);
+	printf("OK\n");
+
+	printf("testing delete... ");
+	FLAC__bitwriter_delete(bw);
+	printf("OK\n");
+
+	printf("\nPASSED!\n");
+	return true;
+}
diff --git a/src/test_libFLAC/bitwriter.h b/src/test_libFLAC/bitwriter.h
new file mode 100644
index 0000000..29cbf89
--- /dev/null
+++ b/src/test_libFLAC/bitwriter.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_BITBUFFER_H
+#define FLAC__TEST_LIBFLAC_BITBUFFER_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_bitwriter(void);
+
+#endif
diff --git a/src/test_libFLAC/crc.c b/src/test_libFLAC/crc.c
new file mode 100644
index 0000000..55f78a7
--- /dev/null
+++ b/src/test_libFLAC/crc.c
@@ -0,0 +1,274 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2018  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/crc.h"
+#include "crc.h"
+
+static FLAC__uint8 crc8_update_ref(FLAC__byte byte, FLAC__uint8 crc);
+static FLAC__uint16 crc16_update_ref(FLAC__byte byte, FLAC__uint16 crc);
+
+static FLAC__bool test_crc8(const FLAC__byte *data, size_t size);
+static FLAC__bool test_crc16(const FLAC__byte *data, size_t size);
+static FLAC__bool test_crc16_update(const FLAC__byte *data, size_t size);
+static FLAC__bool test_crc16_32bit_words(const FLAC__uint32 *words, size_t size);
+static FLAC__bool test_crc16_64bit_words(const FLAC__uint64 *words, size_t size);
+
+#define DATA_SIZE 32768
+
+FLAC__bool test_crc(void)
+{
+	uint32_t i;
+	FLAC__byte data[DATA_SIZE] = { 0 };
+
+	/* Initialize data reproducibly with pseudo-random values. */
+	for (i = 1; i < DATA_SIZE; i++)
+		data[i] = crc8_update_ref(i % 256, data[i - 1]);
+
+	printf("\n+++ libFLAC unit test: crc\n\n");
+
+	if (! test_crc8(data, DATA_SIZE))
+		return false;
+
+	if (! test_crc16(data, DATA_SIZE))
+		return false;
+
+	if (! test_crc16_update(data, DATA_SIZE))
+		return false;
+
+	if (! test_crc16_32bit_words((FLAC__uint32 *)data, DATA_SIZE / 4))
+		return false;
+
+	if (! test_crc16_64bit_words((FLAC__uint64 *)data, DATA_SIZE / 8))
+		return false;
+
+	printf("\nPASSED!\n");
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Reference implementations of CRC-8 and CRC-16 to check against. */
+
+#define CRC8_POLYNOMIAL 0x07
+
+static FLAC__uint8 crc8_update_ref(FLAC__byte byte, FLAC__uint8 crc)
+{
+    uint32_t i;
+
+    crc ^= byte;
+
+    for (i = 0; i < 8; i++) {
+        crc = (crc << 1) ^ ((crc >> 7) ? CRC8_POLYNOMIAL : 0);
+    }
+
+    return crc;
+}
+
+#define CRC16_POLYNOMIAL 0x8005
+
+static FLAC__uint16 crc16_update_ref(FLAC__byte byte, FLAC__uint16 crc)
+{
+    uint32_t i;
+
+    crc ^= byte << 8;
+
+    for (i = 0; i < 8; i++) {
+        crc = (crc << 1) ^ ((crc >> 15) ? CRC16_POLYNOMIAL : 0);
+    }
+
+    return crc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static FLAC__bool test_crc8(const FLAC__byte *data, size_t size)
+{
+	uint32_t i;
+	FLAC__uint8 crc0,crc1;
+
+	printf("testing FLAC__crc8 ... ");
+
+	crc0 = 0;
+	crc1 = FLAC__crc8(data, 0);
+
+	if (crc1 != crc0) {
+		printf("FAILED, FLAC__crc8 returned non-zero CRC for zero bytes of data\n");
+		return false;
+	}
+
+	for (i = 0; i < size; i++) {
+		crc0 = crc8_update_ref(data[i], crc0);
+		crc1 = FLAC__crc8(data, i + 1);
+
+		if (crc1 != crc0) {
+			printf("FAILED, FLAC__crc8 result did not match reference CRC for %u bytes of test data\n", i + 1);
+			return false;
+		}
+	}
+
+	printf("OK\n");
+
+	return true;
+}
+
+static FLAC__bool test_crc16(const FLAC__byte *data, size_t size)
+{
+	uint32_t i;
+	FLAC__uint16 crc0,crc1;
+
+	printf("testing FLAC__crc16 ... ");
+
+	crc0 = 0;
+	crc1 = FLAC__crc16(data, 0);
+
+	if (crc1 != crc0) {
+		printf("FAILED, FLAC__crc16 returned non-zero CRC for zero bytes of data\n");
+		return false;
+	}
+
+	for (i = 0; i < size; i++) {
+		crc0 = crc16_update_ref(data[i], crc0);
+		crc1 = FLAC__crc16(data, i + 1);
+
+		if (crc1 != crc0) {
+			printf("FAILED, FLAC__crc16 result did not match reference CRC for %u bytes of test data\n", i + 1);
+			return false;
+		}
+	}
+
+	printf("OK\n");
+
+	return true;
+}
+
+static FLAC__bool test_crc16_update(const FLAC__byte *data, size_t size)
+{
+	uint32_t i;
+	FLAC__uint16 crc0,crc1;
+
+	printf("testing FLAC__CRC16_UPDATE macro ... ");
+
+	crc0 = 0;
+	crc1 = 0;
+
+	for (i = 0; i < size; i++) {
+		crc0 = crc16_update_ref(data[i], crc0);
+		crc1 = FLAC__CRC16_UPDATE(data[i], crc1);
+
+		if (crc1 != crc0) {
+			printf("FAILED, FLAC__CRC16_UPDATE result did not match reference CRC after %u bytes of test data\n", i + 1);
+			return false;
+		}
+	}
+
+	printf("OK\n");
+
+	return true;
+}
+
+static FLAC__bool test_crc16_32bit_words(const FLAC__uint32 *words, size_t size)
+{
+	uint32_t n,i,k;
+	FLAC__uint16 crc0,crc1;
+
+	for (n = 1; n <= 16; n++) {
+		printf("testing FLAC__crc16_update_words32 (length=%i) ... ", n);
+
+		crc0 = 0;
+		crc1 = 0;
+
+		for (i = 0; i <= size - n; i += n) {
+			for (k = 0; k < n; k++) {
+				crc0 = crc16_update_ref( words[i + k] >> 24,         crc0);
+				crc0 = crc16_update_ref((words[i + k] >> 16) & 0xFF, crc0);
+				crc0 = crc16_update_ref((words[i + k] >>  8) & 0xFF, crc0);
+				crc0 = crc16_update_ref( words[i + k]        & 0xFF, crc0);
+			}
+
+			crc1 = FLAC__crc16_update_words32(words + i, n, crc1);
+
+			if (crc1 != crc0) {
+				printf("FAILED, FLAC__crc16_update_words32 result did not match reference CRC after %u words of test data\n", i + n);
+				return false;
+			}
+		}
+
+		crc1 = FLAC__crc16_update_words32(words, 0, crc1);
+
+		if (crc1 != crc0) {
+			printf("FAILED, FLAC__crc16_update_words32 called with zero bytes changed CRC value\n");
+			return false;
+		}
+
+		printf("OK\n");
+	}
+
+	return true;
+}
+
+static FLAC__bool test_crc16_64bit_words(const FLAC__uint64 *words, size_t size)
+{
+	uint32_t n,i,k;
+	FLAC__uint16 crc0,crc1;
+
+	for (n = 1; n <= 16; n++) {
+		printf("testing FLAC__crc16_update_words64 (length=%i) ... ", n);
+
+		crc0 = 0;
+		crc1 = 0;
+
+		for (i = 0; i <= size - n; i += n) {
+			for (k = 0; k < n; k++) {
+				crc0 = crc16_update_ref( words[i + k] >> 56,         crc0);
+				crc0 = crc16_update_ref((words[i + k] >> 48) & 0xFF, crc0);
+				crc0 = crc16_update_ref((words[i + k] >> 40) & 0xFF, crc0);
+				crc0 = crc16_update_ref((words[i + k] >> 32) & 0xFF, crc0);
+				crc0 = crc16_update_ref((words[i + k] >> 24) & 0xFF, crc0);
+				crc0 = crc16_update_ref((words[i + k] >> 16) & 0xFF, crc0);
+				crc0 = crc16_update_ref((words[i + k] >>  8) & 0xFF, crc0);
+				crc0 = crc16_update_ref( words[i + k]        & 0xFF, crc0);
+			}
+
+			crc1 = FLAC__crc16_update_words64(words + i, n, crc1);
+
+			if (crc1 != crc0) {
+				printf("FAILED, FLAC__crc16_update_words64 result did not match reference CRC after %u words of test data\n", i + n);
+				return false;
+			}
+		}
+
+		crc1 = FLAC__crc16_update_words64(words, 0, crc1);
+
+		if (crc1 != crc0) {
+			printf("FAILED, FLAC__crc16_update_words64 called with zero bytes changed CRC value\n");
+			return false;
+		}
+
+		printf("OK\n");
+	}
+
+	return true;
+}
diff --git a/src/test_libFLAC/crc.h b/src/test_libFLAC/crc.h
new file mode 100644
index 0000000..bac055d
--- /dev/null
+++ b/src/test_libFLAC/crc.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2018  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_CRC_H
+#define FLAC__TEST_LIBFLAC_CRC_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_crc(void);
+
+#endif
diff --git a/src/test_libFLAC/decoders.c b/src/test_libFLAC/decoders.c
new file mode 100644
index 0000000..e9d52e9
--- /dev/null
+++ b/src/test_libFLAC/decoders.c
@@ -0,0 +1,1058 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "decoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "share/safe_str.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+
+typedef enum {
+	LAYER_STREAM = 0, /* FLAC__stream_decoder_init_[ogg_]stream() without seeking */
+	LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_[ogg_]stream() with seeking */
+	LAYER_FILE, /* FLAC__stream_decoder_init_[ogg_]FILE() */
+	LAYER_FILENAME /* FLAC__stream_decoder_init_[ogg_]file() */
+} Layer;
+
+static const char * const LayerString[] = {
+	"Stream",
+	"Seekable Stream",
+	"FILE*",
+	"Filename"
+};
+
+typedef struct {
+	Layer layer;
+	FILE *file;
+	char filename[512];
+	uint32_t current_metadata_number;
+	FLAC__bool ignore_errors;
+	FLAC__bool error_occurred;
+} StreamDecoderClientData;
+
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *expected_metadata_sequence_[9];
+static uint32_t num_expected_;
+static FLAC__off_t flacfilesize_;
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+	return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+	printf("ERROR: %s\n", msg);
+	return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
+{
+	FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder);
+
+	if(msg)
+		printf("FAILED, %s", msg);
+	else
+		printf("FAILED");
+
+	printf(", state = %u (%s)\n", (uint32_t)state, FLAC__StreamDecoderStateString[state]);
+
+	return false;
+}
+
+static void open_test_file(StreamDecoderClientData * pdcd, int is_ogg, const char * mode)
+{
+	pdcd->file = flac_fopen(flacfilename(is_ogg), mode);
+	safe_strncpy(pdcd->filename, flacfilename(is_ogg), sizeof (pdcd->filename));
+}
+
+static void init_metadata_blocks_(void)
+{
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_(void)
+{
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static FLAC__bool generate_file_(FLAC__bool is_ogg)
+{
+	printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":"");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &padding_;
+	expected_metadata_sequence_[num_expected_++] = &seektable_;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
+	expected_metadata_sequence_[num_expected_++] = &unknown_;
+	/* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
+
+	if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
+		return die_("creating the encoded file");
+
+	return true;
+}
+
+static FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+	const size_t requested_bytes = *bytes;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in read callback is NULL\n");
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+	}
+
+	if(dcd->error_occurred)
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+	if(feof(dcd->file)) {
+		*bytes = 0;
+		return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+	}
+	else if(requested_bytes > 0) {
+		*bytes = fread(buffer, 1, requested_bytes, dcd->file);
+		if(*bytes == 0) {
+			if(feof(dcd->file))
+				return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+			else
+				return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		}
+		else {
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+		}
+	}
+	else
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+static FLAC__StreamDecoderSeekStatus stream_decoder_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in seek callback is NULL\n");
+		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+	}
+
+	if(dcd->error_occurred)
+		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+
+	if(fseeko(dcd->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) {
+		dcd->error_occurred = true;
+		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+	}
+
+	return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+static FLAC__StreamDecoderTellStatus stream_decoder_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+	FLAC__off_t offset;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in tell callback is NULL\n");
+		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+	}
+
+	if(dcd->error_occurred)
+		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+
+	offset = ftello(dcd->file);
+	*absolute_byte_offset = (FLAC__uint64)offset;
+
+	if(offset < 0) {
+		dcd->error_occurred = true;
+		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+	}
+
+	return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+static FLAC__StreamDecoderLengthStatus stream_decoder_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+	StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in length callback is NULL\n");
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+	}
+
+	if(dcd->error_occurred)
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+	*stream_length = (FLAC__uint64)flacfilesize_;
+	return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+static FLAC__bool stream_decoder_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+	StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in eof callback is NULL\n");
+		return true;
+	}
+
+	if(dcd->error_occurred)
+		return true;
+
+	return feof(dcd->file);
+}
+
+static FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+	(void)decoder, (void)buffer;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in write callback is NULL\n");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	if(dcd->error_occurred)
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+	if(
+		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+	) {
+		printf("content... ");
+		fflush(stdout);
+	}
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in metadata callback is NULL\n");
+		return;
+	}
+
+	if(dcd->error_occurred)
+		return;
+
+	if (metadata->type == FLAC__METADATA_TYPE_APPLICATION) {
+		printf ("%u ('%c%c%c%c')... ", dcd->current_metadata_number, metadata->data.application.id [0], metadata->data.application.id [1], metadata->data.application.id [2], metadata->data.application.id [3]);
+	}
+	else {
+		printf("%u... ", dcd->current_metadata_number);
+	}
+	fflush(stdout);
+
+
+	if(dcd->current_metadata_number >= num_expected_) {
+		(void)die_("got more metadata blocks than expected");
+		dcd->error_occurred = true;
+	}
+	else {
+		if(!mutils__compare_block(expected_metadata_sequence_[dcd->current_metadata_number], metadata)) {
+			(void)die_("metadata block mismatch");
+			dcd->error_occurred = true;
+		}
+	}
+	dcd->current_metadata_number++;
+}
+
+static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in error callback is NULL\n");
+		return;
+	}
+
+	if(!dcd->ignore_errors) {
+		printf("ERROR: got error callback: err = %u (%s)\n", (uint32_t)status, FLAC__StreamDecoderErrorStatusString[status]);
+		dcd->error_occurred = true;
+	}
+}
+
+static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, StreamDecoderClientData *dcd, FLAC__bool is_ogg)
+{
+	FLAC__StreamDecoderInitStatus init_status;
+
+	if(!FLAC__stream_decoder_set_md5_checking(decoder, true))
+		return die_s_("at FLAC__stream_decoder_set_md5_checking(), returned false", decoder);
+
+	/* for FLAC__stream_encoder_init_FILE(), the FLAC__stream_encoder_finish() closes the file so we have to keep re-opening: */
+	if(dcd->layer == LAYER_FILE) {
+		printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+		open_test_file(dcd, is_ogg, "rb");
+		if(0 == dcd->file) {
+			printf("ERROR (%s)\n", strerror(errno));
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	switch(dcd->layer) {
+		case LAYER_STREAM:
+			printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+				FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd)
+			;
+			break;
+		case LAYER_SEEKABLE_STREAM:
+			printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+				FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+			break;
+		case LAYER_FILE:
+			printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+				FLAC__stream_decoder_init_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+			break;
+		case LAYER_FILENAME:
+			printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+				FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+			break;
+		default:
+			die_("internal error 000");
+			return false;
+	}
+	if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+		return die_s_(0, decoder);
+	printf("OK\n");
+
+	dcd->current_metadata_number = 0;
+
+	if(dcd->layer < LAYER_FILE && fseeko(dcd->file, 0, SEEK_SET) < 0) {
+		printf("FAILED rewinding input, errno = %d\n", errno);
+		return false;
+	}
+
+	printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_finish()... ");
+	if(!FLAC__stream_decoder_finish(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	return true;
+}
+
+static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
+{
+	FLAC__StreamDecoder *decoder;
+	FLAC__StreamDecoderInitStatus init_status;
+	FLAC__StreamDecoderState state;
+	StreamDecoderClientData decoder_client_data;
+	FLAC__bool expect;
+
+	decoder_client_data.layer = layer;
+
+	printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC");
+
+	printf("testing FLAC__stream_decoder_new()... ");
+	decoder = FLAC__stream_decoder_new();
+	if(0 == decoder) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_delete()... ");
+	FLAC__stream_decoder_delete(decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_new()... ");
+	decoder = FLAC__stream_decoder_new();
+	if(0 == decoder) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	switch(layer) {
+		case LAYER_STREAM:
+		case LAYER_SEEKABLE_STREAM:
+			printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0) :
+				FLAC__stream_decoder_init_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+			break;
+		case LAYER_FILE:
+			printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_FILE(decoder, stdin, 0, 0, 0, 0) :
+				FLAC__stream_decoder_init_FILE(decoder, stdin, 0, 0, 0, 0);
+			break;
+		case LAYER_FILENAME:
+			printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) :
+				FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0);
+			break;
+		default:
+			die_("internal error 003");
+			return false;
+	}
+	if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS)
+		return die_s_(0, decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_delete()... ");
+	FLAC__stream_decoder_delete(decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+	printf("testing FLAC__stream_decoder_new()... ");
+	decoder = FLAC__stream_decoder_new();
+	if(0 == decoder) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	if(is_ogg) {
+		printf("testing FLAC__stream_decoder_set_ogg_serial_number()... ");
+		if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, file_utils__ogg_serial_number))
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+	}
+
+	printf("testing FLAC__stream_decoder_set_md5_checking()... ");
+	if(!FLAC__stream_decoder_set_md5_checking(decoder, true))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	if(layer < LAYER_FILENAME) {
+		printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+		open_test_file(&decoder_client_data, is_ogg, "rb");
+		if(0 == decoder_client_data.file) {
+			printf("ERROR (%s)\n", strerror(errno));
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	switch(layer) {
+		case LAYER_STREAM:
+			printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+				FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+			break;
+		case LAYER_SEEKABLE_STREAM:
+			printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+				FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+			break;
+		case LAYER_FILE:
+			printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+				FLAC__stream_decoder_init_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+			break;
+		case LAYER_FILENAME:
+			printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+				FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+			break;
+		default:
+			die_("internal error 009");
+			return false;
+	}
+	if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+		return die_s_(0, decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_get_state()... ");
+	state = FLAC__stream_decoder_get_state(decoder);
+	printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
+
+	decoder_client_data.current_metadata_number = 0;
+	decoder_client_data.ignore_errors = false;
+	decoder_client_data.error_occurred = false;
+
+	printf("testing FLAC__stream_decoder_get_md5_checking()... ");
+	if(!FLAC__stream_decoder_get_md5_checking(decoder)) {
+		printf("FAILED, returned false, expected true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_process_until_end_of_metadata()... ");
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_process_single()... ");
+	if(!FLAC__stream_decoder_process_single(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_skip_single_frame()... ");
+	if(!FLAC__stream_decoder_skip_single_frame(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	if(layer < LAYER_FILE) {
+		printf("testing FLAC__stream_decoder_flush()... ");
+		if(!FLAC__stream_decoder_flush(decoder))
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+
+		decoder_client_data.ignore_errors = true;
+		printf("testing FLAC__stream_decoder_process_single()... ");
+		if(!FLAC__stream_decoder_process_single(decoder))
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+		decoder_client_data.ignore_errors = false;
+	}
+
+	expect = (layer != LAYER_STREAM);
+	printf("testing FLAC__stream_decoder_seek_absolute()... ");
+	if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect)
+		return die_s_(expect? "returned false" : "returned true", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	expect = (layer != LAYER_STREAM);
+	printf("testing FLAC__stream_decoder_seek_absolute()... ");
+	if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect)
+		return die_s_(expect? "returned false" : "returned true", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_get_channels()... ");
+	{
+		uint32_t channels = FLAC__stream_decoder_get_channels(decoder);
+		if(channels != streaminfo_.data.stream_info.channels) {
+			printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels);
+			return false;
+		}
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_get_bits_per_sample()... ");
+	{
+		uint32_t bits_per_sample = FLAC__stream_decoder_get_bits_per_sample(decoder);
+		if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) {
+			printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample);
+			return false;
+		}
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_get_sample_rate()... ");
+	{
+		uint32_t sample_rate = FLAC__stream_decoder_get_sample_rate(decoder);
+		if(sample_rate != streaminfo_.data.stream_info.sample_rate) {
+			printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate);
+			return false;
+		}
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_get_blocksize()... ");
+	{
+		uint32_t blocksize = FLAC__stream_decoder_get_blocksize(decoder);
+		/* value could be anything since we're at the last block, so accept any reasonable answer */
+		printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED");
+		if(blocksize == 0)
+			return false;
+	}
+
+	printf("testing FLAC__stream_decoder_get_channel_assignment()... ");
+	{
+		FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder);
+		printf("returned %u (%s)... OK\n", (uint32_t)ca, FLAC__ChannelAssignmentString[ca]);
+	}
+
+	if(layer < LAYER_FILE) {
+		printf("testing FLAC__stream_decoder_reset()... ");
+		if(!FLAC__stream_decoder_reset(decoder)) {
+			state = FLAC__stream_decoder_get_state(decoder);
+			printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]);
+			return false;
+		}
+		printf("OK\n");
+
+		if(layer == LAYER_STREAM) {
+			/* after a reset() we have to rewind the input ourselves */
+			printf("rewinding input... ");
+			if(fseeko(decoder_client_data.file, 0, SEEK_SET) < 0) {
+				printf("FAILED, errno = %d\n", errno);
+				return false;
+			}
+			printf("OK\n");
+		}
+
+		decoder_client_data.current_metadata_number = 0;
+
+		printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+		if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+			return die_s_("returned false", decoder);
+		printf("OK\n");
+	}
+
+	printf("testing FLAC__stream_decoder_finish()... ");
+	if(!FLAC__stream_decoder_finish(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	/*
+	 * respond all
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application1_;
+		expected_metadata_sequence_[num_expected_++] = &application2_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application1_;
+		expected_metadata_sequence_[num_expected_++] = &application2_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * ignore all
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * respond all, ignore VORBIS_COMMENT
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+	expected_metadata_sequence_[num_expected_++] = &padding_;
+	expected_metadata_sequence_[num_expected_++] = &seektable_;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
+	expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * respond all, ignore APPLICATION
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * respond all, ignore APPLICATION id of app#1
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application2_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application2_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * respond all, ignore APPLICATION id of app#1 & app#2
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #2)... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * ignore all, respond VORBIS_COMMENT
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+	if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * ignore all, respond APPLICATION
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+	if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * ignore all, respond APPLICATION id of app#1
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * ignore all, respond APPLICATION id of app#1 & app#2
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #2)... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &application1_;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+	if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application1_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+	else {
+		expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+		expected_metadata_sequence_[num_expected_++] = &padding_;
+		expected_metadata_sequence_[num_expected_++] = &seektable_;
+		expected_metadata_sequence_[num_expected_++] = &application1_;
+		expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+		expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+		expected_metadata_sequence_[num_expected_++] = &picture_;
+		expected_metadata_sequence_[num_expected_++] = &unknown_;
+	}
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	/*
+	 * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+	 */
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+	if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+	if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+		return die_s_("returned false", decoder);
+	printf("OK\n");
+
+	num_expected_ = 0;
+	expected_metadata_sequence_[num_expected_++] = &application2_;
+
+	if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+		return false;
+
+	if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
+		fclose(decoder_client_data.file);
+
+	printf("testing FLAC__stream_decoder_delete()... ");
+	FLAC__stream_decoder_delete(decoder);
+	printf("OK\n");
+
+	printf("\nPASSED!\n");
+
+	return true;
+}
+
+FLAC__bool test_decoders(void)
+{
+	FLAC__bool is_ogg = false;
+
+	while(1) {
+		init_metadata_blocks_();
+
+		if(!generate_file_(is_ogg))
+			return false;
+
+		if(!test_stream_decoder(LAYER_STREAM, is_ogg))
+			return false;
+
+		if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg))
+			return false;
+
+		if(!test_stream_decoder(LAYER_FILE, is_ogg))
+			return false;
+
+		if(!test_stream_decoder(LAYER_FILENAME, is_ogg))
+			return false;
+
+		(void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+		free_metadata_blocks_();
+
+		if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+			break;
+		is_ogg = true;
+	}
+
+	return true;
+}
diff --git a/src/test_libFLAC/decoders.h b/src/test_libFLAC/decoders.h
new file mode 100644
index 0000000..5fb2ae5
--- /dev/null
+++ b/src/test_libFLAC/decoders.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_DECODERS_H
+#define FLAC__TEST_LIBFLAC_DECODERS_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_decoders(void);
+
+#endif
diff --git a/src/test_libFLAC/encoders.c b/src/test_libFLAC/encoders.c
new file mode 100644
index 0000000..7aefe79
--- /dev/null
+++ b/src/test_libFLAC/encoders.c
@@ -0,0 +1,519 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "encoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_encoder.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+
+typedef enum {
+	LAYER_STREAM = 0, /* FLAC__stream_encoder_init_[ogg_]stream() without seeking */
+	LAYER_SEEKABLE_STREAM, /* FLAC__stream_encoder_init_[ogg_]stream() with seeking */
+	LAYER_FILE, /* FLAC__stream_encoder_init_[ogg_]FILE() */
+	LAYER_FILENAME /* FLAC__stream_encoder_init_[ogg_]file() */
+} Layer;
+
+static const char * const LayerString[] = {
+	"Stream",
+	"Seekable Stream",
+	"FILE*",
+	"Filename"
+};
+
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ };
+static const uint32_t num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+	return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+	printf("ERROR: %s\n", msg);
+	return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamEncoder *encoder)
+{
+	FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(encoder);
+
+	if(msg)
+		printf("FAILED, %s", msg);
+	else
+		printf("FAILED");
+
+	printf(", state = %u (%s)\n", (uint32_t)state, FLAC__StreamEncoderStateString[state]);
+	if(state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+		FLAC__StreamDecoderState dstate = FLAC__stream_encoder_get_verify_decoder_state(encoder);
+		printf("      verify decoder state = %u (%s)\n", (uint32_t)dstate, FLAC__StreamDecoderStateString[dstate]);
+	}
+
+	return false;
+}
+
+static void init_metadata_blocks_(void)
+{
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_(void)
+{
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static FLAC__StreamEncoderReadStatus stream_encoder_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	FILE *f = (FILE*)client_data;
+	(void)encoder;
+	if(*bytes > 0) {
+		*bytes = fread(buffer, sizeof(FLAC__byte), *bytes, f);
+		if(ferror(f))
+			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;
+}
+
+static FLAC__StreamEncoderWriteStatus stream_encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data)
+{
+	FILE *f = (FILE*)client_data;
+	(void)encoder, (void)samples, (void)current_frame;
+	if(fwrite(buffer, 1, bytes, f) != bytes)
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+	else
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static FLAC__StreamEncoderSeekStatus stream_encoder_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	FILE *f = (FILE*)client_data;
+	(void)encoder;
+	if(fseeko(f, (long)absolute_byte_offset, SEEK_SET) < 0)
+		return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+	else
+		return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+static FLAC__StreamEncoderTellStatus stream_encoder_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	FILE *f = (FILE*)client_data;
+	FLAC__off_t pos;
+	(void)encoder;
+	if((pos = ftello(f)) < 0)
+		return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+	else {
+		*absolute_byte_offset = (FLAC__uint64)pos;
+		return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+	}
+}
+
+static void stream_encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	(void)encoder, (void)metadata, (void)client_data;
+}
+
+static void stream_encoder_progress_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data)
+{
+	(void)encoder, (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate, (void)client_data;
+}
+
+static FLAC__bool test_stream_encoder(Layer layer, FLAC__bool is_ogg)
+{
+	FLAC__StreamEncoder *encoder;
+	FLAC__StreamEncoderInitStatus init_status;
+	FLAC__StreamEncoderState state;
+	FLAC__StreamDecoderState dstate;
+	FILE *file = 0;
+	FLAC__int32 samples[1024];
+	FLAC__int32 *samples_array[1];
+	uint32_t i;
+
+	samples_array[0] = samples;
+
+	printf("\n+++ libFLAC unit test: FLAC__StreamEncoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC":"FLAC");
+
+	printf("testing FLAC__stream_encoder_new()... ");
+	encoder = FLAC__stream_encoder_new();
+	if(0 == encoder) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	if(is_ogg) {
+		printf("testing FLAC__stream_encoder_set_ogg_serial_number()... ");
+		if(!FLAC__stream_encoder_set_ogg_serial_number(encoder, file_utils__ogg_serial_number))
+			return die_s_("returned false", encoder);
+		printf("OK\n");
+	}
+
+	printf("testing FLAC__stream_encoder_set_verify()... ");
+	if(!FLAC__stream_encoder_set_verify(encoder, true))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_streamable_subset()... ");
+	if(!FLAC__stream_encoder_set_streamable_subset(encoder, true))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_channels()... ");
+	if(!FLAC__stream_encoder_set_channels(encoder, streaminfo_.data.stream_info.channels))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_bits_per_sample()... ");
+	if(!FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo_.data.stream_info.bits_per_sample))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_sample_rate()... ");
+	if(!FLAC__stream_encoder_set_sample_rate(encoder, streaminfo_.data.stream_info.sample_rate))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_compression_level()... ");
+	if(!FLAC__stream_encoder_set_compression_level(encoder, (uint32_t)(-1)))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_blocksize()... ");
+	if(!FLAC__stream_encoder_set_blocksize(encoder, streaminfo_.data.stream_info.min_blocksize))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_do_mid_side_stereo()... ");
+	if(!FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_loose_mid_side_stereo()... ");
+	if(!FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_max_lpc_order()... ");
+	if(!FLAC__stream_encoder_set_max_lpc_order(encoder, 0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_qlp_coeff_precision()... ");
+	if(!FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_do_qlp_coeff_prec_search()... ");
+	if(!FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_do_escape_coding()... ");
+	if(!FLAC__stream_encoder_set_do_escape_coding(encoder, false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_do_exhaustive_model_search()... ");
+	if(!FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_min_residual_partition_order()... ");
+	if(!FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_max_residual_partition_order()... ");
+	if(!FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_rice_parameter_search_dist()... ");
+	if(!FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_total_samples_estimate()... ");
+	if(!FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo_.data.stream_info.total_samples))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_set_metadata()... ");
+	if(!FLAC__stream_encoder_set_metadata(encoder, metadata_sequence_, num_metadata_))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	if(layer < LAYER_FILENAME) {
+		printf("opening file for FLAC output... ");
+		file = flac_fopen(flacfilename(is_ogg), "w+b");
+		if(0 == file) {
+			printf("ERROR (%s)\n", strerror(errno));
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	switch(layer) {
+		case LAYER_STREAM:
+			printf("testing FLAC__stream_encoder_init_%sstream()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, stream_encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, stream_encoder_metadata_callback_, /*client_data=*/file) :
+				FLAC__stream_encoder_init_stream(encoder, stream_encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, stream_encoder_metadata_callback_, /*client_data=*/file);
+			break;
+		case LAYER_SEEKABLE_STREAM:
+			printf("testing FLAC__stream_encoder_init_%sstream()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_encoder_init_ogg_stream(encoder, stream_encoder_read_callback_, stream_encoder_write_callback_, stream_encoder_seek_callback_, stream_encoder_tell_callback_, /*metadata_callback=*/0, /*client_data=*/file) :
+				FLAC__stream_encoder_init_stream(encoder, stream_encoder_write_callback_, stream_encoder_seek_callback_, stream_encoder_tell_callback_, /*metadata_callback=*/0, /*client_data=*/file);
+			break;
+		case LAYER_FILE:
+			printf("testing FLAC__stream_encoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_encoder_init_ogg_FILE(encoder, file, stream_encoder_progress_callback_, /*client_data=*/0) :
+				FLAC__stream_encoder_init_FILE(encoder, file, stream_encoder_progress_callback_, /*client_data=*/0);
+			break;
+		case LAYER_FILENAME:
+			printf("testing FLAC__stream_encoder_init_%sfile()... ", is_ogg? "ogg_":"");
+			init_status = is_ogg?
+				FLAC__stream_encoder_init_ogg_file(encoder, flacfilename(is_ogg), stream_encoder_progress_callback_, /*client_data=*/0) :
+				FLAC__stream_encoder_init_file(encoder, flacfilename(is_ogg), stream_encoder_progress_callback_, /*client_data=*/0);
+			break;
+		default:
+			die_("internal error 001");
+			return false;
+	}
+	if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+		return die_s_(0, encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_state()... ");
+	state = FLAC__stream_encoder_get_state(encoder);
+	printf("returned state = %u (%s)... OK\n", (uint32_t)state, FLAC__StreamEncoderStateString[state]);
+
+	printf("testing FLAC__stream_encoder_get_verify_decoder_state()... ");
+	dstate = FLAC__stream_encoder_get_verify_decoder_state(encoder);
+	printf("returned state = %u (%s)... OK\n", (uint32_t)dstate, FLAC__StreamDecoderStateString[dstate]);
+
+	{
+		FLAC__uint64 absolute_sample;
+		uint32_t frame_number;
+		uint32_t channel;
+		uint32_t sample;
+		FLAC__int32 expected;
+		FLAC__int32 got;
+
+		printf("testing FLAC__stream_encoder_get_verify_decoder_error_stats()... ");
+		FLAC__stream_encoder_get_verify_decoder_error_stats(encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+		printf("OK\n");
+	}
+
+	printf("testing FLAC__stream_encoder_get_verify()... ");
+	if(FLAC__stream_encoder_get_verify(encoder) != true) {
+		printf("FAILED, expected true, got false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_streamable_subset()... ");
+	if(FLAC__stream_encoder_get_streamable_subset(encoder) != true) {
+		printf("FAILED, expected true, got false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_do_mid_side_stereo()... ");
+	if(FLAC__stream_encoder_get_do_mid_side_stereo(encoder) != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_loose_mid_side_stereo()... ");
+	if(FLAC__stream_encoder_get_loose_mid_side_stereo(encoder) != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_channels()... ");
+	if(FLAC__stream_encoder_get_channels(encoder) != streaminfo_.data.stream_info.channels) {
+		printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, FLAC__stream_encoder_get_channels(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_bits_per_sample()... ");
+	if(FLAC__stream_encoder_get_bits_per_sample(encoder) != streaminfo_.data.stream_info.bits_per_sample) {
+		printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, FLAC__stream_encoder_get_bits_per_sample(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_sample_rate()... ");
+	if(FLAC__stream_encoder_get_sample_rate(encoder) != streaminfo_.data.stream_info.sample_rate) {
+		printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, FLAC__stream_encoder_get_sample_rate(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_blocksize()... ");
+	if(FLAC__stream_encoder_get_blocksize(encoder) != streaminfo_.data.stream_info.min_blocksize) {
+		printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, FLAC__stream_encoder_get_blocksize(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_max_lpc_order()... ");
+	if(FLAC__stream_encoder_get_max_lpc_order(encoder) != 0) {
+		printf("FAILED, expected %d, got %u\n", 0, FLAC__stream_encoder_get_max_lpc_order(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_qlp_coeff_precision()... ");
+	(void)FLAC__stream_encoder_get_qlp_coeff_precision(encoder);
+	/* we asked the encoder to auto select this so we accept anything */
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_do_qlp_coeff_prec_search()... ");
+	if(FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder) != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_do_escape_coding()... ");
+	if(FLAC__stream_encoder_get_do_escape_coding(encoder) != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_do_exhaustive_model_search()... ");
+	if(FLAC__stream_encoder_get_do_exhaustive_model_search(encoder) != false) {
+		printf("FAILED, expected false, got true\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_min_residual_partition_order()... ");
+	if(FLAC__stream_encoder_get_min_residual_partition_order(encoder) != 0) {
+		printf("FAILED, expected %d, got %u\n", 0, FLAC__stream_encoder_get_min_residual_partition_order(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_max_residual_partition_order()... ");
+	if(FLAC__stream_encoder_get_max_residual_partition_order(encoder) != 0) {
+		printf("FAILED, expected %d, got %u\n", 0, FLAC__stream_encoder_get_max_residual_partition_order(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_rice_parameter_search_dist()... ");
+	if(FLAC__stream_encoder_get_rice_parameter_search_dist(encoder) != 0) {
+		printf("FAILED, expected %d, got %u\n", 0, FLAC__stream_encoder_get_rice_parameter_search_dist(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_get_total_samples_estimate()... ");
+	if(FLAC__stream_encoder_get_total_samples_estimate(encoder) != streaminfo_.data.stream_info.total_samples) {
+		printf("FAILED, expected %" PRIu64 ", got %" PRIu64 "\n", streaminfo_.data.stream_info.total_samples, FLAC__stream_encoder_get_total_samples_estimate(encoder));
+		return false;
+	}
+	printf("OK\n");
+
+	/* init the dummy sample buffer */
+	for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+		samples[i] = i & 7;
+
+	printf("testing FLAC__stream_encoder_process()... ");
+	if(!FLAC__stream_encoder_process(encoder, (const FLAC__int32 * const *)samples_array, sizeof(samples) / sizeof(FLAC__int32)))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_process_interleaved()... ");
+	if(!FLAC__stream_encoder_process_interleaved(encoder, samples, sizeof(samples) / sizeof(FLAC__int32)))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	printf("testing FLAC__stream_encoder_finish()... ");
+	if(!FLAC__stream_encoder_finish(encoder))
+		return die_s_("returned false", encoder);
+	printf("OK\n");
+
+	if(layer < LAYER_FILE)
+		fclose(file);
+
+	printf("testing FLAC__stream_encoder_delete()... ");
+	FLAC__stream_encoder_delete(encoder);
+	printf("OK\n");
+
+	printf("\nPASSED!\n");
+
+	return true;
+}
+
+FLAC__bool test_encoders(void)
+{
+	FLAC__bool is_ogg = false;
+
+	while(1) {
+		init_metadata_blocks_();
+
+		if(!test_stream_encoder(LAYER_STREAM, is_ogg))
+			return false;
+
+		if(!test_stream_encoder(LAYER_SEEKABLE_STREAM, is_ogg))
+			return false;
+
+		if(!test_stream_encoder(LAYER_FILE, is_ogg))
+			return false;
+
+		if(!test_stream_encoder(LAYER_FILENAME, is_ogg))
+			return false;
+
+		(void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+		free_metadata_blocks_();
+
+		if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+			break;
+		is_ogg = true;
+	}
+
+	return true;
+}
diff --git a/src/test_libFLAC/encoders.h b/src/test_libFLAC/encoders.h
new file mode 100644
index 0000000..a2ca557
--- /dev/null
+++ b/src/test_libFLAC/encoders.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_ENCODERS_H
+#define FLAC__TEST_LIBFLAC_ENCODERS_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_encoders(void);
+
+#endif
diff --git a/src/test_libFLAC/endswap.c b/src/test_libFLAC/endswap.c
new file mode 100644
index 0000000..b10dc3e
--- /dev/null
+++ b/src/test_libFLAC/endswap.c
@@ -0,0 +1,111 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "share/compat.h"
+#include "FLAC/assert.h"
+#include "share/endswap.h"
+#include "private/md5.h"
+#include "endswap.h"
+
+
+FLAC__bool test_endswap(void)
+{
+	int16_t i16 = 0x1234;
+	uint16_t u16 = 0xabcd;
+	int32_t i32 = 0x12345678;
+	uint32_t u32 = 0xabcdef01;
+
+	union {
+		uint8_t bytes[4];
+		uint16_t u16;
+		uint32_t u32;
+	} data;
+
+	printf("\n+++ libFLAC unit test: endswap (%s endian host)\n\n", CPU_IS_LITTLE_ENDIAN ? "little" : "big");
+
+	printf("testing ENDSWAP_16 on int16_t ... ");
+	if (((int16_t) ENDSWAP_16(i16)) == i16) {
+		printf("\nFAILED, ENDSWAP_16(0x%04x) -> 0x%04x == 0x%04x\n", i16, ENDSWAP_16(i16), i16);
+		return false;
+	}
+	if (((int16_t) ENDSWAP_16(ENDSWAP_16(i16))) != i16) {
+		printf("\nFAILED, ENDSWAP_16(ENDSWAP_16(0x%04x)) -> 0x%04x != 0x%04x\n", i16, ENDSWAP_16(ENDSWAP_16(i16)), i16);
+		return false;
+	}
+	puts("OK");
+
+	printf("testing ENDSWAP_16 on uint16_t ... ");
+	if (((uint16_t) ENDSWAP_16(u16)) == u16) {
+		printf("\nFAILED, ENDSWAP_16(0x%04x) -> 0x%04x == 0x%04x\n", u16, ENDSWAP_16(u16), u16);
+		return false;
+	}
+	if (((uint16_t) ENDSWAP_16(ENDSWAP_16(u16))) != u16) {
+		printf("\nFAILED, ENDSWAP_16(ENDSWAP_16(0x%04x)) -> 0x%04x != 0x%04x\n", u16, ENDSWAP_16(ENDSWAP_16(u16)), u16);
+		return false;
+	}
+	puts("OK");
+
+	printf("testing ENDSWAP_32 on int32_t ... ");
+	if (((int32_t) ENDSWAP_32 (i32)) == i32) {
+		printf("\nFAILED, ENDSWAP_32(0x%08x) -> 0x%08x == 0x%08x\n", i32, (uint32_t) ENDSWAP_32 (i32), i32);
+		return false;
+	}
+	if (((int32_t) ENDSWAP_32 (ENDSWAP_32 (i32))) != i32) {
+		printf("\nFAILED, ENDSWAP_32(ENDSWAP_32(0x%08x)) -> 0x%08x != 0x%08x\n", i32, (uint32_t) ENDSWAP_32(ENDSWAP_32 (i32)), i32);
+		return false;
+	}
+	puts("OK");
+
+	printf("testing ENDSWAP_32 on uint32_t ... ");
+	if (((uint32_t) ENDSWAP_32(u32)) == u32) {
+		printf("\nFAILED, ENDSWAP_32(0x%08x) -> 0x%08x == 0x%08x\n", u32, (uint32_t) ENDSWAP_32(u32), u32);
+		return false;
+	}
+	if (((uint32_t) ENDSWAP_32 (ENDSWAP_32(u32))) != u32) {
+		printf("\nFAILED, ENDSWAP_32(ENDSWAP_32(0x%08x)) -> 0x%08x != 0%08x\n", u32, (uint32_t) ENDSWAP_32(ENDSWAP_32(u32)), u32);
+		return false;
+	}
+	puts("OK");
+
+	printf("testing H2LE_16 on uint16_t ... ");
+	data.u16 = H2LE_16(0x1234);
+	if (data.bytes [0] != 0x34 || data.bytes [1] != 0x12) {
+		printf("\nFAILED, H2LE_16(0x%04x) -> { 0x%02x, 0x%02x }\n", data.u16, data.bytes [0] & 0xff, data.bytes [1] & 0xff);
+		return false;
+	}
+	puts("OK");
+
+	printf("testing H2LE_32 on uint32_t ... ");
+	data.u32 = H2LE_32(0x12345678);
+	if (data.bytes [0] != 0x78 || data.bytes [1] != 0x56 || data.bytes [2] != 0x34 || data.bytes [3] != 0x12) {
+		printf("\nFAILED,  H2LE_32(0x%08x) -> { 0x%02x, 0x%02x, 0x%02x, 0x%02x }\n",
+			data.u32, data.bytes [0] & 0xff, data.bytes [1] & 0xff, data.bytes [2] & 0xff, data.bytes [3] & 0xff);
+		return false;
+	}
+	puts("OK");
+
+	printf("\nPASSED!\n");
+	return true;
+}
diff --git a/src/test_libFLAC/endswap.h b/src/test_libFLAC/endswap.h
new file mode 100644
index 0000000..bdd2e74
--- /dev/null
+++ b/src/test_libFLAC/endswap.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_ENDSWAP_H
+#define FLAC__TEST_LIBFLAC_ENDSWAP_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_endswap(void);
+
+#endif
diff --git a/src/test_libFLAC/format.c b/src/test_libFLAC/format.c
new file mode 100644
index 0000000..d57c11d
--- /dev/null
+++ b/src/test_libFLAC/format.c
@@ -0,0 +1,257 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "format.h"
+#include <stdio.h>
+
+static const char *true_false_string_[2] = { "false", "true" };
+
+static struct {
+	uint32_t rate;
+	FLAC__bool valid;
+	FLAC__bool subset;
+} SAMPLE_RATES[] = {
+	{ 0      , false, false },
+	{ 1      , true , true  },
+	{ 9      , true , true  },
+	{ 10     , true , true  },
+	{ 4000   , true , true  },
+	{ 8000   , true , true  },
+	{ 11025  , true , true  },
+	{ 12000  , true , true  },
+	{ 16000  , true , true  },
+	{ 22050  , true , true  },
+	{ 24000  , true , true  },
+	{ 32000  , true , true  },
+	{ 32768  , true , true  },
+	{ 44100  , true , true  },
+	{ 48000  , true , true  },
+	{ 65000  , true , true  },
+	{ 65535  , true , true  },
+	{ 65536  , true , false },
+	{ 65540  , true , true  },
+	{ 65550  , true , true  },
+	{ 65555  , true , false },
+	{ 66000  , true , true  },
+	{ 66001  , true , false },
+	{ 96000  , true , true  },
+	{ 100000 , true , true  },
+	{ 100001 , true , false },
+	{ 192000 , true , true  },
+	{ 500000 , true , true  },
+	{ 500001 , true , false },
+	{ 500010 , true , true  },
+	{ 655349 , true , false },
+	{ 655350 , true , true  },
+	{ 655351 , false, false },
+	{ 655360 , false, false },
+	{ 700000 , false, false },
+	{ 700010 , false, false },
+	{ 1000000, false, false },
+	{ 1100000, false, false }
+};
+
+static struct {
+	const char *string;
+	FLAC__bool valid;
+} VCENTRY_NAMES[] = {
+	{ ""    , true  },
+	{ "a"   , true  },
+	{ "="   , false },
+	{ "a="  , false },
+	{ "\x01", false },
+	{ "\x1f", false },
+	{ "\x7d", true  },
+	{ "\x7e", false },
+	{ "\xff", false }
+};
+
+static struct {
+	uint32_t length;
+	const FLAC__byte *string;
+	FLAC__bool valid;
+} VCENTRY_VALUES[] = {
+	{ 0, (const FLAC__byte*)""            , true  },
+	{ 1, (const FLAC__byte*)""            , true  },
+	{ 1, (const FLAC__byte*)"\x01"        , true  },
+	{ 1, (const FLAC__byte*)"\x7f"        , true  },
+	{ 1, (const FLAC__byte*)"\x80"        , false },
+	{ 1, (const FLAC__byte*)"\x81"        , false },
+	{ 1, (const FLAC__byte*)"\xc0"        , false },
+	{ 1, (const FLAC__byte*)"\xe0"        , false },
+	{ 1, (const FLAC__byte*)"\xf0"        , false },
+	{ 2, (const FLAC__byte*)"\xc0\x41"    , false },
+	{ 2, (const FLAC__byte*)"\xc1\x41"    , false },
+	{ 2, (const FLAC__byte*)"\xc0\x85"    , false }, /* non-shortest form */
+	{ 2, (const FLAC__byte*)"\xc1\x85"    , false }, /* non-shortest form */
+	{ 2, (const FLAC__byte*)"\xc2\x85"    , true  },
+	{ 2, (const FLAC__byte*)"\xe0\x41"    , false },
+	{ 2, (const FLAC__byte*)"\xe1\x41"    , false },
+	{ 2, (const FLAC__byte*)"\xe0\x85"    , false },
+	{ 2, (const FLAC__byte*)"\xe1\x85"    , false },
+	{ 3, (const FLAC__byte*)"\xe0\x85\x41", false },
+	{ 3, (const FLAC__byte*)"\xe1\x85\x41", false },
+	{ 3, (const FLAC__byte*)"\xe0\x85\x80", false }, /* non-shortest form */
+	{ 3, (const FLAC__byte*)"\xe0\x95\x80", false }, /* non-shortest form */
+	{ 3, (const FLAC__byte*)"\xe0\xa5\x80", true  },
+	{ 3, (const FLAC__byte*)"\xe1\x85\x80", true  },
+	{ 3, (const FLAC__byte*)"\xe1\x95\x80", true  },
+	{ 3, (const FLAC__byte*)"\xe1\xa5\x80", true  }
+};
+
+static struct {
+	const FLAC__byte *string;
+	FLAC__bool valid;
+} VCENTRY_VALUES_NT[] = {
+	{ (const FLAC__byte*)""            , true  },
+	{ (const FLAC__byte*)"\x01"        , true  },
+	{ (const FLAC__byte*)"\x7f"        , true  },
+	{ (const FLAC__byte*)"\x80"        , false },
+	{ (const FLAC__byte*)"\x81"        , false },
+	{ (const FLAC__byte*)"\xc0"        , false },
+	{ (const FLAC__byte*)"\xe0"        , false },
+	{ (const FLAC__byte*)"\xf0"        , false },
+	{ (const FLAC__byte*)"\xc0\x41"    , false },
+	{ (const FLAC__byte*)"\xc1\x41"    , false },
+	{ (const FLAC__byte*)"\xc0\x85"    , false }, /* non-shortest form */
+	{ (const FLAC__byte*)"\xc1\x85"    , false }, /* non-shortest form */
+	{ (const FLAC__byte*)"\xc2\x85"    , true  },
+	{ (const FLAC__byte*)"\xe0\x41"    , false },
+	{ (const FLAC__byte*)"\xe1\x41"    , false },
+	{ (const FLAC__byte*)"\xe0\x85"    , false },
+	{ (const FLAC__byte*)"\xe1\x85"    , false },
+	{ (const FLAC__byte*)"\xe0\x85\x41", false },
+	{ (const FLAC__byte*)"\xe1\x85\x41", false },
+	{ (const FLAC__byte*)"\xe0\x85\x80", false }, /* non-shortest form */
+	{ (const FLAC__byte*)"\xe0\x95\x80", false }, /* non-shortest form */
+	{ (const FLAC__byte*)"\xe0\xa5\x80", true  },
+	{ (const FLAC__byte*)"\xe1\x85\x80", true  },
+	{ (const FLAC__byte*)"\xe1\x95\x80", true  },
+	{ (const FLAC__byte*)"\xe1\xa5\x80", true  }
+};
+
+static struct {
+	uint32_t length;
+	const FLAC__byte *string;
+	FLAC__bool valid;
+} VCENTRIES[] = {
+	{ 0, (const FLAC__byte*)""              , false },
+	{ 1, (const FLAC__byte*)"a"             , false },
+	{ 1, (const FLAC__byte*)"="             , true  },
+	{ 2, (const FLAC__byte*)"a="            , true  },
+	{ 2, (const FLAC__byte*)"\x01="         , false },
+	{ 2, (const FLAC__byte*)"\x1f="         , false },
+	{ 2, (const FLAC__byte*)"\x7d="         , true  },
+	{ 2, (const FLAC__byte*)"\x7e="         , false },
+	{ 2, (const FLAC__byte*)"\xff="         , false },
+	{ 3, (const FLAC__byte*)"a=\x01"        , true  },
+	{ 3, (const FLAC__byte*)"a=\x7f"        , true  },
+	{ 3, (const FLAC__byte*)"a=\x80"        , false },
+	{ 3, (const FLAC__byte*)"a=\x81"        , false },
+	{ 3, (const FLAC__byte*)"a=\xc0"        , false },
+	{ 3, (const FLAC__byte*)"a=\xe0"        , false },
+	{ 3, (const FLAC__byte*)"a=\xf0"        , false },
+	{ 4, (const FLAC__byte*)"a=\xc0\x41"    , false },
+	{ 4, (const FLAC__byte*)"a=\xc1\x41"    , false },
+	{ 4, (const FLAC__byte*)"a=\xc0\x85"    , false }, /* non-shortest form */
+	{ 4, (const FLAC__byte*)"a=\xc1\x85"    , false }, /* non-shortest form */
+	{ 4, (const FLAC__byte*)"a=\xc2\x85"    , true  },
+	{ 4, (const FLAC__byte*)"a=\xe0\x41"    , false },
+	{ 4, (const FLAC__byte*)"a=\xe1\x41"    , false },
+	{ 4, (const FLAC__byte*)"a=\xe0\x85"    , false },
+	{ 4, (const FLAC__byte*)"a=\xe1\x85"    , false },
+	{ 5, (const FLAC__byte*)"a=\xe0\x85\x41", false },
+	{ 5, (const FLAC__byte*)"a=\xe1\x85\x41", false },
+	{ 5, (const FLAC__byte*)"a=\xe0\x85\x80", false }, /* non-shortest form */
+	{ 5, (const FLAC__byte*)"a=\xe0\x95\x80", false }, /* non-shortest form */
+	{ 5, (const FLAC__byte*)"a=\xe0\xa5\x80", true  },
+	{ 5, (const FLAC__byte*)"a=\xe1\x85\x80", true  },
+	{ 5, (const FLAC__byte*)"a=\xe1\x95\x80", true  },
+	{ 5, (const FLAC__byte*)"a=\xe1\xa5\x80", true  }
+};
+
+FLAC__bool test_format(void)
+{
+	uint32_t i;
+
+	printf("\n+++ libFLAC unit test: format\n\n");
+
+	for(i = 0; i < sizeof(SAMPLE_RATES)/sizeof(SAMPLE_RATES[0]); i++) {
+		printf("testing FLAC__format_sample_rate_is_valid(%u)... ", SAMPLE_RATES[i].rate);
+		if(FLAC__format_sample_rate_is_valid(SAMPLE_RATES[i].rate) != SAMPLE_RATES[i].valid) {
+			printf("FAILED, expected %s, got %s\n", true_false_string_[SAMPLE_RATES[i].valid], true_false_string_[!SAMPLE_RATES[i].valid]);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	for(i = 0; i < sizeof(SAMPLE_RATES)/sizeof(SAMPLE_RATES[0]); i++) {
+		printf("testing FLAC__format_sample_rate_is_subset(%u)... ", SAMPLE_RATES[i].rate);
+		if(FLAC__format_sample_rate_is_subset(SAMPLE_RATES[i].rate) != SAMPLE_RATES[i].subset) {
+			printf("FAILED, expected %s, got %s\n", true_false_string_[SAMPLE_RATES[i].subset], true_false_string_[!SAMPLE_RATES[i].subset]);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	for(i = 0; i < sizeof(VCENTRY_NAMES)/sizeof(VCENTRY_NAMES[0]); i++) {
+		printf("testing FLAC__format_vorbiscomment_entry_name_is_legal(\"%s\")... ", VCENTRY_NAMES[i].string);
+		if(FLAC__format_vorbiscomment_entry_name_is_legal(VCENTRY_NAMES[i].string) != VCENTRY_NAMES[i].valid) {
+			printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_NAMES[i].valid], true_false_string_[!VCENTRY_NAMES[i].valid]);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	for(i = 0; i < sizeof(VCENTRY_VALUES)/sizeof(VCENTRY_VALUES[0]); i++) {
+		printf("testing FLAC__format_vorbiscomment_entry_value_is_legal(\"%s\", %u)... ", VCENTRY_VALUES[i].string, VCENTRY_VALUES[i].length);
+		if(FLAC__format_vorbiscomment_entry_value_is_legal(VCENTRY_VALUES[i].string, VCENTRY_VALUES[i].length) != VCENTRY_VALUES[i].valid) {
+			printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_VALUES[i].valid], true_false_string_[!VCENTRY_VALUES[i].valid]);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	for(i = 0; i < sizeof(VCENTRY_VALUES_NT)/sizeof(VCENTRY_VALUES_NT[0]); i++) {
+		printf("testing FLAC__format_vorbiscomment_entry_value_is_legal(\"%s\", -1)... ", VCENTRY_VALUES_NT[i].string);
+		if(FLAC__format_vorbiscomment_entry_value_is_legal(VCENTRY_VALUES_NT[i].string, (uint32_t)(-1)) != VCENTRY_VALUES_NT[i].valid) {
+			printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_VALUES_NT[i].valid], true_false_string_[!VCENTRY_VALUES_NT[i].valid]);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	for(i = 0; i < sizeof(VCENTRIES)/sizeof(VCENTRIES[0]); i++) {
+		printf("testing FLAC__format_vorbiscomment_entry_is_legal(\"%s\", %u)... ", VCENTRIES[i].string, VCENTRIES[i].length);
+		if(FLAC__format_vorbiscomment_entry_is_legal(VCENTRIES[i].string, VCENTRIES[i].length) != VCENTRIES[i].valid) {
+			printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRIES[i].valid], true_false_string_[!VCENTRIES[i].valid]);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	printf("\nPASSED!\n");
+	return true;
+}
diff --git a/src/test_libFLAC/format.h b/src/test_libFLAC/format.h
new file mode 100644
index 0000000..a71d1cd
--- /dev/null
+++ b/src/test_libFLAC/format.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_FORMAT_H
+#define FLAC__TEST_LIBFLAC_FORMAT_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_format(void);
+
+#endif
diff --git a/src/test_libFLAC/main.c b/src/test_libFLAC/main.c
new file mode 100644
index 0000000..e627b86
--- /dev/null
+++ b/src/test_libFLAC/main.c
@@ -0,0 +1,64 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "bitreader.h"
+#include "bitwriter.h"
+#include "crc.h"
+#include "decoders.h"
+#include "encoders.h"
+#include "endswap.h"
+#include "format.h"
+#include "metadata.h"
+#include "md5.h"
+
+int main(void)
+{
+	if(!test_endswap())
+		return 1;
+
+	if(!test_crc())
+		return 1;
+
+	if(!test_md5())
+		return 1;
+
+	if(!test_bitreader())
+		return 1;
+
+	if(!test_bitwriter())
+		return 1;
+
+	if(!test_format())
+		return 1;
+
+	if(!test_encoders())
+		return 1;
+
+	if(!test_decoders())
+		return 1;
+
+	if(!test_metadata())
+		return 1;
+
+	return 0;
+}
diff --git a/src/test_libFLAC/matrix b/src/test_libFLAC/matrix
new file mode 100644
index 0000000..a78ecf3
--- /dev/null
+++ b/src/test_libFLAC/matrix
@@ -0,0 +1,69 @@
+#if 0
+level 1
+
+4 delete	middle block	nopad
+1 delete	middle block	pad
+1 delete	last block	nopad
+1 delete	last block	pad
+1 insert	middle block	nopad
+1 insert	middle block	equalpad
+1 insert	middle block	smallpad
+1 insert	middle block	smallpad+1
+1 insert	middle block	biggerpad
+1 insert	last block	X
+1 set	middle block	smaller	nopad
+1 set	middle block	smaller	pad
+1 set	last block	smaller	nopad
+1 set	last block	smaller	pad
+1 set	middle block	bigger	nopad
+1 set	middle block	bigger	equalpad
+1 set	middle block	bigger	smallpad
+1 set	middle block	bigger	smallpad+1
+1 set	middle block	bigger	biggerpad
+1 set	last block	bigger	nopad
+1 set	middle block	equal	X
+2 set	last block	equal	X
+
+level 2
+
+FLAC__bool FLAC__metadata_chain_write()
+
+1	newsize==oldsize
+	newsize>oldsize
+b		no use_padding
+c		use_padding, last block is not padding
+g		use_padding, last block is padding of insufficient length
+h		use_padding, last block is padding, but padding header straddles border (can't do it)
+j		use_padding, last block is padding of exact sufficient length (padding totally consumed)
+i		use_padding, last block is padding of abundant length (padding is reduced)
+	newsize<oldsize
+a		no use_padding
+d		use_padding, last block is not padding, delta is < 4
+e		use_padding, last block is not padding, delta is >= 4
+f		use_padding, last block is padding
+
+void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain);
+void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain);
+
+S:34	A:1234
+a:shrink A->30	write nopad
+S:34	A:30
+b:grow A->32	write nopad
+S:34	A:32
+c:grow A->40	write pad
+S:34	A:40
+d:shrink A->37	write pad
+S:34	A:37
+e:shrink A->33	write pad
+S:34	A:33	P:0
+f:shrink A->20	write pad
+S:34	A:20	P:13
+g:grow A->40	write pad
+S:34	A:40	P:13
+h:grow A->54	write pad
+S:34	A:54	P:13
+i:grow A->60	write pad
+S:34	A:60	P:7
+j:grow A->71	write pad
+S:34	A:71
+#endif
diff --git a/src/test_libFLAC/md5.c b/src/test_libFLAC/md5.c
new file mode 100644
index 0000000..147a76c
--- /dev/null
+++ b/src/test_libFLAC/md5.c
@@ -0,0 +1,221 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/md5.h"
+#include "md5.h"
+
+
+static FLAC__bool test_md5_clear_context(void);
+static FLAC__bool test_md5_codec(void);
+static FLAC__bool test_md5_accumulate(const FLAC__int32 * const * signal,uint32_t channels, uint32_t samples, uint32_t bytes_per_sample, const FLAC__byte target_digest [16]);
+
+FLAC__bool test_md5(void)
+{
+	printf("\n+++ libFLAC unit test: md5\n\n");
+
+	if (! test_md5_clear_context())
+		return false;
+
+	if (! test_md5_codec())
+		return false;
+
+	printf("\nPASSED!\n");
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static FLAC__bool test_md5_clear_context(void)
+{
+	FLAC__MD5Context ctx;
+	FLAC__byte digest[16];
+	FLAC__byte target[16] = { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e };
+	uint32_t k ;
+	char * cptr;
+
+	printf("testing FLAC__MD5Init ... ");
+	FLAC__MD5Init (&ctx);
+	if (ctx.buf[0] != 0x67452301) {
+		printf("FAILED!\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing that FLAC__MD5Final clears the MD5Context ... ");
+	FLAC__MD5Final(digest, &ctx);
+	cptr = (char*) &ctx ;
+	for (k = 0 ; k < sizeof (ctx) ; k++) {
+		if (cptr [k]) {
+			printf("FAILED, MD5 ctx has not been cleared after FLAC__MD5Final\n");
+			return false;
+		}
+	}
+	printf("OK\n");
+
+	printf("testing digest correct for zero data ... ");
+	if (memcmp(digest, target, sizeof (digest))) {
+		printf("\nFAILED, expected MD5 sum ");
+		for (k = 0 ; k < 16 ; k++)
+			printf("%02x", (target [k] & 0xff));
+		printf (" but got ");
+		for (k = 0 ; k < 16 ; k++)
+			printf("%02x", (digest [k] & 0xff));
+		puts("\n");
+		return false;
+	}
+	puts("OK");
+
+	return true;
+}
+
+static FLAC__byte target_digests [8][4][16] =
+{	/* 1 channel */
+	{ 	/* 1 byte per sample */
+		{ 0xc1, 0x9a, 0x5b, 0xeb, 0x57, 0x8f, 0x26, 0xeb, 0xfb, 0x34, 0x7c, 0xef, 0x04, 0x31, 0x6d, 0x7d },
+		/* 2 bytes per sample */
+		{ 0xd4, 0x78, 0x90, 0xd3, 0xa9, 0x17, 0x4e, 0x76, 0xca, 0x4d, 0x27, 0x20, 0x98, 0x36, 0x8b, 0x2e },
+		/* 3 bytes per sample */
+		{ 0x5a, 0x4b, 0xd6, 0xac, 0xa1, 0x70, 0x84, 0x19, 0x7c, 0x0d, 0xfb, 0x5b, 0xa9, 0x7b, 0xcb, 0x54 },
+		/* 4 bytes per sample */
+		{ 0x79, 0xd5, 0x7a, 0x32, 0x06, 0x0b, 0xfe, 0x46, 0xa3, 0xe7, 0xba, 0xc5, 0xf7, 0x48, 0x6f, 0x50 }
+	},
+
+	/* 2 channels */
+	{
+		{ 0x89, 0xac, 0xcf, 0x91, 0xf1, 0x8c, 0xea, 0xab, 0x46, 0x12, 0x74, 0xbc, 0x4e, 0x82, 0xbe, 0x7d },
+		{ 0xb9, 0x17, 0x16, 0x5b, 0xd8, 0x1c, 0xc8, 0x4e, 0x5a, 0x28, 0xfb, 0xba, 0x87, 0x74, 0x76, 0x44 },
+		{ 0xec, 0x63, 0x92, 0xca, 0x4f, 0x6b, 0x9e, 0xb1, 0x9f, 0xec, 0x3b, 0x2c, 0x15, 0x30, 0xfd, 0x2a },
+		{ 0x05, 0x4d, 0xfd, 0xb8, 0x9d, 0x8a, 0xa2, 0xdd, 0x26, 0x47, 0xc6, 0xfb, 0x4f, 0x23, 0x67, 0x6d }
+	},
+
+	/* 3 channels */
+	{
+		{ 0xad, 0x05, 0xda, 0xf3, 0x7a, 0xa1, 0x94, 0xdb, 0x0c, 0x61, 0x06, 0xb2, 0x94, 0x39, 0x6c, 0xa9 },
+		{ 0x8b, 0xcc, 0x41, 0x4d, 0xe9, 0xe3, 0xc2, 0x61, 0x61, 0x8a, 0x8b, 0x22, 0xc6, 0x4e, 0xac, 0xa7 },
+		{ 0x8a, 0xce, 0x97, 0xc1, 0x86, 0xae, 0xbc, 0x73, 0x88, 0x8b, 0x35, 0x5a, 0x37, 0x33, 0xf9, 0xcf },
+		{ 0x69, 0x59, 0xe8, 0x38, 0x29, 0x80, 0x80, 0x21, 0xb1, 0xd2, 0xba, 0xf6, 0x28, 0xd6, 0x6a, 0x83 }
+	},
+
+	/* 4 channels */
+	{
+		{ 0x61, 0x40, 0x75, 0xef, 0x22, 0xf1, 0x0f, 0xa6, 0x08, 0x6c, 0x88, 0xff, 0x2c, 0x4e, 0x98, 0x0b },
+		{ 0xa0, 0x77, 0x3a, 0x59, 0x4a, 0xbf, 0xd0, 0x5c, 0xcc, 0xe3, 0xb9, 0x83, 0x2b, 0xf3, 0xdf, 0x1a },
+		{ 0xdb, 0xd7, 0xf1, 0x82, 0x13, 0x60, 0x42, 0x7c, 0x84, 0xe6, 0xcf, 0x30, 0xab, 0xa2, 0x64, 0xf1 },
+		{ 0x4a, 0x9a, 0xad, 0x53, 0x05, 0x74, 0xb1, 0x1c, 0xb8, 0xd4, 0xae, 0x78, 0x13, 0xf6, 0x2a, 0x11 }
+	},
+
+	/* 5 channels */
+	{
+		{ 0xcc, 0xca, 0x44, 0xc0, 0x54, 0xe2, 0xc9, 0xba, 0x99, 0x32, 0xc9, 0x65, 0xf3, 0x3e, 0x44, 0x34},
+		{ 0x40, 0x38, 0x6a, 0xdd, 0xde, 0x89, 0x10, 0x3c, 0x8e, 0xec, 0xdf, 0x15, 0x53, 0x4c, 0x2c, 0x92 },
+		{ 0xc8, 0x95, 0x0a, 0x7c, 0x17, 0x30, 0xc0, 0xac, 0x8e, 0x34, 0xdb, 0x79, 0x76, 0x64, 0x7c, 0x6e },
+		{ 0x3f, 0x06, 0x11, 0x8a, 0x8d, 0x80, 0xb5, 0x4f, 0x8b, 0xb5, 0x8e, 0xb3, 0x27, 0x3e, 0x41, 0xe8 }
+	},
+
+	/* 6 channels */
+	{
+		{ 0x61, 0xe4, 0xbd, 0xb1, 0xc0, 0x2f, 0xf4, 0x4c, 0x6e, 0x09, 0x5a, 0xbd, 0x90, 0x18, 0x8b, 0x62 },
+		{ 0x47, 0xe7, 0x6e, 0x3b, 0x18, 0x86, 0x60, 0x1b, 0x09, 0x62, 0xc6, 0xc9, 0x7c, 0x4c, 0x03, 0xb5 },
+		{ 0x70, 0x57, 0xbf, 0x67, 0x66, 0x0f, 0xe3, 0x0a, 0x6c, 0xd2, 0x97, 0x66, 0xa2, 0xd2, 0xe4, 0x79 },
+		{ 0xaa, 0x3f, 0xc7, 0xf5, 0x7a, 0xa5, 0x46, 0xf7, 0xea, 0xe3, 0xd5, 0x1a, 0xa4, 0x62, 0xbe, 0xfa }
+	},
+
+	/* 7 channels */
+	{
+		{ 0x7c, 0x8d, 0xd2, 0x8c, 0xfd, 0x91, 0xbb, 0x77, 0x6f, 0x0e, 0xf0, 0x39, 0x1f, 0x39, 0xc4, 0xac },
+		{ 0xfb, 0xab, 0x18, 0x3f, 0x1e, 0x1d, 0xa5, 0x77, 0xe0, 0x5c, 0xea, 0x45, 0x6f, 0x64, 0xa4, 0x64 },
+		{ 0xe3, 0xac, 0x33, 0x50, 0xc1, 0xb1, 0x93, 0xfb, 0xca, 0x4b, 0x15, 0xcb, 0x2d, 0xcd, 0xd5, 0xef },
+		{ 0x10, 0xfb, 0x02, 0x83, 0x76, 0x0d, 0xe5, 0xd2, 0x3b, 0xb1, 0x4c, 0x78, 0x3b, 0x73, 0xf7, 0x1a }
+	},
+
+	/* 8 channels */
+	{
+		{ 0x65, 0x7b, 0xe5, 0x92, 0xe2, 0x1c, 0x95, 0x3e, 0xd7, 0x2f, 0x64, 0xa0, 0x86, 0xec, 0x1a, 0xed },
+		{ 0x9d, 0x04, 0x8f, 0xa4, 0xea, 0x10, 0xec, 0xb8, 0xa3, 0x88, 0xe2, 0x5d, 0x3c, 0xe2, 0xfb, 0x94 },
+		{ 0x5a, 0xd3, 0xd2, 0x75, 0x6a, 0xfa, 0xa7, 0x42, 0xf3, 0xbf, 0x0e, 0xbc, 0x90, 0x2a, 0xf8, 0x5f },
+		{ 0x76, 0xe1, 0xe5, 0xf6, 0xe3, 0x44, 0x08, 0x29, 0xae, 0x79, 0x19, 0xeb, 0xa8, 0x57, 0x16, 0x2a }
+	}
+};
+
+#define MAX_CHANNEL_COUNT	8
+#define MD5_SAMPLE_COUNT	64
+
+static FLAC__bool test_md5_codec(void)
+{
+	FLAC__int32 arrays[MAX_CHANNEL_COUNT][MD5_SAMPLE_COUNT], *pointer[MAX_CHANNEL_COUNT], **signal;
+	uint32_t chan, byte_size, seed = 0x12345679;
+
+	/* Set up signal data using a trivial Linear Congruent PRNG. */
+	signal = &pointer[0];
+	for (chan = 0 ; chan < MAX_CHANNEL_COUNT ; chan ++) {
+		uint32_t k;
+		pointer[chan] = arrays [chan];
+		for (k = 0 ; k < MD5_SAMPLE_COUNT ; k++) {
+			seed = seed * 1103515245 + 12345;
+			arrays[chan][k] = seed;
+		}
+	}
+
+	for (chan = 1 ; chan <= MAX_CHANNEL_COUNT ; chan ++) {
+		for (byte_size = 1 ; byte_size <= 4 ; byte_size ++) {
+			if (! test_md5_accumulate((const FLAC__int32 * const *) signal, chan, MD5_SAMPLE_COUNT, byte_size, target_digests[chan-1][byte_size-1]))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+static FLAC__bool test_md5_accumulate(const FLAC__int32 * const * signal, uint32_t channels, uint32_t samples, uint32_t bytes_per_sample, const FLAC__byte target_digest [16])
+{
+	FLAC__MD5Context ctx;
+	FLAC__byte digest[16];
+
+	memset(&ctx, 0, sizeof (ctx));
+
+	printf("testing FLAC__MD5Accumulate (samples=%u, channels=%u, bytes_per_sample=%u) ... ", samples, channels, bytes_per_sample);
+
+	FLAC__MD5Init(&ctx);
+	FLAC__MD5Accumulate(&ctx, signal, channels, samples, bytes_per_sample);
+	FLAC__MD5Final(digest, &ctx);
+
+	if (memcmp(digest, target_digest, sizeof (digest))) {
+		int k ;
+
+		printf("\nFAILED, expected MD5 sum ");
+		for (k = 0 ; k < 16 ; k++)
+			printf("%02x", (target_digest [k] & 0xff));
+		printf (" but got ");
+		for (k = 0 ; k < 16 ; k++)
+			printf("%02x", (digest [k] & 0xff));
+		puts("\n");
+		return false;
+	}
+
+	printf("OK\n");
+	return true;
+}
diff --git a/src/test_libFLAC/md5.h b/src/test_libFLAC/md5.h
new file mode 100644
index 0000000..dc9e8ff
--- /dev/null
+++ b/src/test_libFLAC/md5.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_MD5_H
+#define FLAC__TEST_LIBFLAC_MD5_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_md5(void);
+
+#endif
diff --git a/src/test_libFLAC/metadata.c b/src/test_libFLAC/metadata.c
new file mode 100644
index 0000000..771ea65
--- /dev/null
+++ b/src/test_libFLAC/metadata.c
@@ -0,0 +1,41 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "metadata.h"
+#include <stdio.h>
+
+extern FLAC__bool test_metadata_object(void);
+extern FLAC__bool test_metadata_file_manipulation(void);
+
+FLAC__bool test_metadata(void)
+{
+	if(!test_metadata_object())
+		return false;
+
+	if(!test_metadata_file_manipulation())
+		return false;
+
+	printf("\nPASSED!\n");
+
+	return true;
+}
diff --git a/src/test_libFLAC/metadata.h b/src/test_libFLAC/metadata.h
new file mode 100644
index 0000000..f6cae82
--- /dev/null
+++ b/src/test_libFLAC/metadata.h
@@ -0,0 +1,29 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_METADATA_H
+#define FLAC__TEST_LIBFLAC_METADATA_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_metadata(void);
+FLAC__bool test_metadata_file_manipulation(void);
+FLAC__bool test_metadata_object(void);
+
+#endif
diff --git a/src/test_libFLAC/metadata_manip.c b/src/test_libFLAC/metadata_manip.c
new file mode 100644
index 0000000..4f74f7c
--- /dev/null
+++ b/src/test_libFLAC/metadata_manip.c
@@ -0,0 +1,2140 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy()/memset() */
+#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 <unistd.h> /* for chown(), unlink() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "share/macros.h"
+#include "share/safe_str.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+#include "metadata.h"
+
+
+/******************************************************************************
+	The general strategy of these tests (for interface levels 1 and 2) is
+	to create a dummy FLAC file with a known set of initial metadata
+	blocks, then keep a mirror locally of what we expect the metadata to be
+	after each operation.  Then testing becomes a simple matter of running
+	a FLAC__StreamDecoder over the dummy file after each operation, comparing
+	the decoded metadata to what's in our local copy.  If there are any
+	differences in the metadata, or the actual audio data is corrupted, we
+	will catch it while decoding.
+******************************************************************************/
+
+typedef struct {
+	FLAC__bool error_occurred;
+} decoder_client_struct;
+
+typedef struct {
+	FLAC__StreamMetadata *blocks[64];
+	uint32_t num_blocks;
+} our_metadata_struct;
+
+/* our copy of the metadata in flacfilename() */
+static our_metadata_struct our_metadata_;
+
+/* the current block number that corresponds to the position of the iterator we are testing */
+static uint32_t mc_our_block_number_ = 0;
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+	return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+	printf("ERROR: %s\n", msg);
+	return false;
+}
+
+static FLAC__bool die_c_(const char *msg, FLAC__Metadata_ChainStatus status)
+{
+	printf("ERROR: %s\n", msg);
+	printf("       status=%s\n", FLAC__Metadata_ChainStatusString[status]);
+	return false;
+}
+
+static FLAC__bool die_ss_(const char *msg, FLAC__Metadata_SimpleIterator *iterator)
+{
+	printf("ERROR: %s\n", msg);
+	printf("       status=%s\n", FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iterator)]);
+	return false;
+}
+
+static void *malloc_or_die_(size_t size)
+{
+	void *x = malloc(size);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size);
+		exit(1);
+	}
+	return x;
+}
+
+static char *strdup_or_die_(const char *s)
+{
+	char *x = strdup(s);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+		exit(1);
+	}
+	return x;
+}
+
+/* functions for working with our metadata copy */
+
+static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetadata *block, uint32_t position, FLAC__bool copy)
+{
+	uint32_t i;
+	FLAC__StreamMetadata *obj = block;
+	FLAC__ASSERT(position < our_metadata_.num_blocks);
+	if(copy) {
+		if(0 == (obj = FLAC__metadata_object_clone(block)))
+			return die_("during FLAC__metadata_object_clone()");
+	}
+	FLAC__metadata_object_delete(our_metadata_.blocks[position]);
+	our_metadata_.blocks[position] = obj;
+
+	/* set the is_last flags */
+	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+		our_metadata_.blocks[i]->is_last = false;
+	our_metadata_.blocks[i]->is_last = true;
+
+	return true;
+}
+
+static FLAC__bool insert_to_our_metadata_(FLAC__StreamMetadata *block, uint32_t position, FLAC__bool copy)
+{
+	uint32_t i;
+	FLAC__StreamMetadata *obj = block;
+	if(copy) {
+		if(0 == (obj = FLAC__metadata_object_clone(block)))
+			return die_("during FLAC__metadata_object_clone()");
+	}
+	if(position > our_metadata_.num_blocks) {
+		position = our_metadata_.num_blocks;
+	}
+	else {
+		for(i = our_metadata_.num_blocks; i > position; i--)
+			our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
+	}
+	our_metadata_.blocks[position] = obj;
+	our_metadata_.num_blocks++;
+
+	/* set the is_last flags */
+	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+		our_metadata_.blocks[i]->is_last = false;
+	our_metadata_.blocks[i]->is_last = true;
+
+	return true;
+}
+
+static void delete_from_our_metadata_(uint32_t position)
+{
+	uint32_t i;
+	FLAC__ASSERT(position < our_metadata_.num_blocks);
+	FLAC__metadata_object_delete(our_metadata_.blocks[position]);
+	for(i = position; i < our_metadata_.num_blocks - 1; i++)
+		our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
+	our_metadata_.num_blocks--;
+
+	/* set the is_last flags */
+	if(our_metadata_.num_blocks > 0) {
+		for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+			our_metadata_.blocks[i]->is_last = false;
+		our_metadata_.blocks[i]->is_last = true;
+	}
+}
+
+/*
+ * This wad of functions supports filename- and callback-based chain reading/writing.
+ * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
+ */
+static FLAC__bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+	static const char *tempfile_suffix = ".metadata_edit";
+	size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1;
+
+	*tempfilename = malloc(dest_len);
+	if (*tempfilename == NULL)
+		return false;
+	safe_strncpy(*tempfilename, filename, dest_len);
+	safe_strncat(*tempfilename, tempfile_suffix, dest_len);
+
+	*tempfile = flac_fopen(*tempfilename, "wb");
+	if (*tempfile == NULL)
+		return false;
+
+	return true;
+}
+
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+	if (*tempfile != NULL) {
+		(void)fclose(*tempfile);
+		*tempfile = 0;
+	}
+
+	if (*tempfilename != NULL) {
+		(void)flac_unlink(*tempfilename);
+		free(*tempfilename);
+		*tempfilename = 0;
+	}
+}
+
+static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != tempfile);
+	FLAC__ASSERT(0 != tempfilename);
+	FLAC__ASSERT(0 != *tempfilename);
+
+	if(0 != *tempfile) {
+		(void)fclose(*tempfile);
+		*tempfile = 0;
+	}
+
+#if defined _MSC_VER || 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);
+		return false;
+	}
+#endif
+
+	if(0 != flac_rename(*tempfilename, filename)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+
+	cleanup_tempfile_(tempfile, tempfilename);
+
+	return true;
+}
+
+static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+	return (0 == flac_stat(filename, stats));
+}
+
+static void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+	struct timespec srctime[2] = {};
+	srctime[0].tv_sec = stats->st_atime;
+	srctime[1].tv_sec = stats->st_mtime;
+#else
+	struct utimbuf srctime;
+	srctime.actime = stats->st_atime;
+	srctime.modtime = stats->st_mtime;
+#endif
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+
+	(void)flac_chmod(filename, stats->st_mode);
+	(void)flac_utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __MINGW32__
+	FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1));
+	FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid));
+#endif
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
+{
+	FILE *stream = (FILE*)handle;
+	size_t ret = fwrite(ptr, size, nmemb, stream);
+	if(!ferror(stream))
+		fflush(stream);
+	return ret;
+}
+#endif
+
+static int chain_seek_cb_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+	FLAC__off_t o = (FLAC__off_t)offset;
+	FLAC__ASSERT(offset == o);
+	return fseeko((FILE*)handle, o, whence);
+}
+
+static FLAC__int64 chain_tell_cb_(FLAC__IOHandle handle)
+{
+	return ftello((FILE*)handle);
+}
+
+static int chain_eof_cb_(FLAC__IOHandle handle)
+{
+	return feof((FILE*)handle);
+}
+
+static FLAC__bool write_chain_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats, FLAC__bool filename_based, const char *filename)
+{
+	if(filename_based)
+		return FLAC__metadata_chain_write(chain, use_padding, preserve_file_stats);
+	else {
+		FLAC__IOCallbacks callbacks;
+
+		memset(&callbacks, 0, sizeof(callbacks));
+		callbacks.read = (FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+		callbacks.write = chain_write_cb_;
+#else
+		callbacks.write = (FLAC__IOCallback_Write)fwrite;
+#endif
+		callbacks.seek = chain_seek_cb_;
+		callbacks.eof = chain_eof_cb_;
+
+		if(FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+			struct flac_stat_s stats;
+			FILE *file, *tempfile = 0;
+			char *tempfilename;
+			if(preserve_file_stats) {
+				if(!get_file_stats_(filename, &stats))
+					return false;
+			}
+			if(0 == (file = flac_fopen(filename, "rb")))
+				return false; /*@@@@ chain status still says OK though */
+			if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
+				fclose(file);
+				cleanup_tempfile_(&tempfile, &tempfilename);
+				return false; /*@@@@ chain status still says OK though */
+			}
+			if(!FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, use_padding, (FLAC__IOHandle)file, callbacks, (FLAC__IOHandle)tempfile, callbacks)) {
+				fclose(file);
+				fclose(tempfile);
+				return false;
+			}
+			fclose(file);
+			fclose(tempfile);
+			file = tempfile = 0;
+			if(!transport_tempfile_(filename, &tempfile, &tempfilename))
+				return false;
+			if(preserve_file_stats)
+				set_file_stats_(filename, &stats);
+		}
+		else {
+			FILE *file = flac_fopen(filename, "r+b");
+			if(0 == file)
+				return false; /*@@@@ chain status still says OK though */
+			if(!FLAC__metadata_chain_write_with_callbacks(chain, use_padding, (FLAC__IOHandle)file, callbacks))
+				return false;
+			fclose(file);
+		}
+	}
+
+	return true;
+}
+
+static FLAC__bool read_chain_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool filename_based, FLAC__bool is_ogg)
+{
+	if(filename_based)
+		return is_ogg?
+			FLAC__metadata_chain_read_ogg(chain, flacfilename(is_ogg)) :
+			FLAC__metadata_chain_read(chain, flacfilename(is_ogg))
+		;
+	else {
+		FLAC__IOCallbacks callbacks;
+
+		memset(&callbacks, 0, sizeof(callbacks));
+		callbacks.read = (FLAC__IOCallback_Read)fread;
+		callbacks.seek = chain_seek_cb_;
+		callbacks.tell = chain_tell_cb_;
+
+		{
+			FLAC__bool ret;
+			FILE *file = flac_fopen(filename, "rb");
+			if(0 == file)
+				return false; /*@@@@ chain status still says OK though */
+			ret = is_ogg?
+				FLAC__metadata_chain_read_ogg_with_callbacks(chain, (FLAC__IOHandle)file, callbacks) :
+				FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)
+			;
+			fclose(file);
+			return ret;
+		}
+	}
+}
+
+/* function for comparing our metadata to a FLAC__Metadata_Chain */
+
+static FLAC__bool compare_chain_(FLAC__Metadata_Chain *chain, uint32_t current_position, FLAC__StreamMetadata *current_block)
+{
+	uint32_t i;
+	FLAC__Metadata_Iterator *iterator;
+	FLAC__StreamMetadata *block;
+	FLAC__bool next_ok = true;
+
+	FLAC__ASSERT(0 != chain);
+
+	printf("\tcomparing chain... ");
+	fflush(stdout);
+
+	if(0 == (iterator = FLAC__metadata_iterator_new()))
+		return die_("allocating memory for iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	i = 0;
+	do {
+		printf("%u... ", i);
+		fflush(stdout);
+
+		if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) {
+			FLAC__metadata_iterator_delete(iterator);
+			return die_("getting block from iterator");
+		}
+
+		if(!mutils__compare_block(our_metadata_.blocks[i], block)) {
+			FLAC__metadata_iterator_delete(iterator);
+			return die_("metadata block mismatch");
+		}
+
+		i++;
+		next_ok = FLAC__metadata_iterator_next(iterator);
+	} while(i < our_metadata_.num_blocks && next_ok);
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	if(next_ok)
+		return die_("chain has more blocks than expected");
+
+	if(i < our_metadata_.num_blocks)
+		return die_("short block count in chain");
+
+	if(0 != current_block) {
+		printf("CURRENT_POSITION... ");
+		fflush(stdout);
+
+		if(!mutils__compare_block(our_metadata_.blocks[current_position], current_block))
+			return die_("metadata block mismatch");
+	}
+
+	printf("PASSED\n");
+
+	return true;
+}
+
+/* decoder callbacks for checking the file */
+
+static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	(void)decoder, (void)buffer, (void)client_data;
+
+	if(
+		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+	) {
+		printf("content... ");
+		fflush(stdout);
+	}
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+/* this version pays no attention to the metadata */
+static void decoder_metadata_callback_null_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	(void)decoder, (void)metadata, (void)client_data;
+
+	printf("%u... ", mc_our_block_number_);
+	fflush(stdout);
+
+	mc_our_block_number_++;
+}
+
+/* this version is used when we want to compare to our metadata copy */
+static void decoder_metadata_callback_compare_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	decoder_client_struct *dcd = (decoder_client_struct*)client_data;
+
+	(void)decoder;
+
+	/* don't bother checking if we've already hit an error */
+	if(dcd->error_occurred)
+		return;
+
+	printf("%u... ", mc_our_block_number_);
+	fflush(stdout);
+
+	if(mc_our_block_number_ >= our_metadata_.num_blocks) {
+		(void)die_("got more metadata blocks than expected");
+		dcd->error_occurred = true;
+	}
+	else {
+		if(!mutils__compare_block(our_metadata_.blocks[mc_our_block_number_], metadata)) {
+			(void)die_("metadata block mismatch");
+			dcd->error_occurred = true;
+		}
+	}
+	mc_our_block_number_++;
+}
+
+static void decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	decoder_client_struct *dcd = (decoder_client_struct*)client_data;
+	(void)decoder;
+
+	dcd->error_occurred = true;
+	printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (uint32_t)status);
+}
+
+static FLAC__bool generate_file_(FLAC__bool include_extras, FLAC__bool is_ogg)
+{
+	FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
+	FLAC__StreamMetadata *metadata[4];
+	uint32_t i = 0, n = 0;
+
+	printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
+
+	while(our_metadata_.num_blocks > 0)
+		delete_from_our_metadata_(0);
+
+	streaminfo.is_last = false;
+	streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
+	streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+	streaminfo.data.stream_info.min_blocksize = 576;
+	streaminfo.data.stream_info.max_blocksize = 576;
+	streaminfo.data.stream_info.min_framesize = 0;
+	streaminfo.data.stream_info.max_framesize = 0;
+	streaminfo.data.stream_info.sample_rate = 44100;
+	streaminfo.data.stream_info.channels = 1;
+	streaminfo.data.stream_info.bits_per_sample = 8;
+	streaminfo.data.stream_info.total_samples = 0;
+	memset(streaminfo.data.stream_info.md5sum, 0, 16);
+
+	{
+		const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING);
+		vorbiscomment.is_last = false;
+		vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+		vorbiscomment.length = (4 + vendor_string_length) + 4;
+		vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
+		vorbiscomment.data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1);
+		memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
+		vorbiscomment.data.vorbis_comment.num_comments = 0;
+		vorbiscomment.data.vorbis_comment.comments = 0;
+	}
+
+	{
+		if (0 == (cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)))
+			return die_("priming our metadata");
+		cuesheet->is_last = false;
+		safe_strncpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN", sizeof(cuesheet->data.cue_sheet.media_catalog_number));
+		cuesheet->data.cue_sheet.lead_in = 123;
+		cuesheet->data.cue_sheet.is_cd = false;
+		if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
+			return die_("priming our metadata");
+		cuesheet->data.cue_sheet.tracks[0].number = 1;
+		if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
+			return die_("priming our metadata");
+	}
+
+	{
+		picture.is_last = false;
+		picture.type = FLAC__METADATA_TYPE_PICTURE;
+		picture.length =
+			(
+				FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+				FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+				FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+				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 /* will add the length for the data later */
+			) / 8
+		;
+		picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+		picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
+		picture.length += strlen(picture.data.picture.mime_type);
+		picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+		picture.length += strlen((const char *)picture.data.picture.description);
+		picture.data.picture.width = 300;
+		picture.data.picture.height = 300;
+		picture.data.picture.depth = 24;
+		picture.data.picture.colors = 0;
+		picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+		picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
+		picture.length += picture.data.picture.data_length;
+	}
+
+	padding.is_last = true;
+	padding.type = FLAC__METADATA_TYPE_PADDING;
+	padding.length = 1234;
+
+	metadata[n++] = &vorbiscomment;
+	if(include_extras) {
+		metadata[n++] = cuesheet;
+		metadata[n++] = &picture;
+	}
+	metadata[n++] = &padding;
+
+	if(
+		!insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) ||
+		!insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) ||
+		(include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
+		(include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) ||
+		!insert_to_our_metadata_(&padding, i++, /*copy=*/true)
+	)
+		return die_("priming our metadata");
+
+	if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
+		return die_("creating the encoded file");
+
+	free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
+	free(picture.data.picture.mime_type);
+	free(picture.data.picture.description);
+	free(picture.data.picture.data);
+	if(!include_extras)
+		FLAC__metadata_object_delete(cuesheet);
+
+	return true;
+}
+
+static FLAC__bool test_file_(FLAC__bool is_ogg, FLAC__StreamDecoderMetadataCallback metadata_callback)
+{
+	const char *filename = flacfilename(is_ogg);
+	FLAC__StreamDecoder *decoder;
+	decoder_client_struct decoder_client_data;
+
+	FLAC__ASSERT(0 != metadata_callback);
+
+	mc_our_block_number_ = 0;
+	decoder_client_data.error_occurred = false;
+
+	printf("\ttesting '%s'... ", filename);
+	fflush(stdout);
+
+	if(0 == (decoder = FLAC__stream_decoder_new()))
+		return die_("couldn't allocate decoder instance");
+
+	FLAC__stream_decoder_set_md5_checking(decoder, true);
+	FLAC__stream_decoder_set_metadata_respond_all(decoder);
+	if(
+		(is_ogg?
+			FLAC__stream_decoder_init_ogg_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data) :
+			FLAC__stream_decoder_init_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data)
+		) != FLAC__STREAM_DECODER_INIT_STATUS_OK
+	) {
+		(void)FLAC__stream_decoder_finish(decoder);
+		FLAC__stream_decoder_delete(decoder);
+		return die_("initializing decoder\n");
+	}
+	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) {
+		(void)FLAC__stream_decoder_finish(decoder);
+		FLAC__stream_decoder_delete(decoder);
+		return die_("decoding file\n");
+	}
+
+	(void)FLAC__stream_decoder_finish(decoder);
+	FLAC__stream_decoder_delete(decoder);
+
+	if(decoder_client_data.error_occurred)
+		return false;
+
+	if(mc_our_block_number_ != our_metadata_.num_blocks)
+		return die_("short metadata block count");
+
+	printf("PASSED\n");
+	return true;
+}
+
+static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only)
+{
+	if(!grabbag__file_change_stats(filename, read_only))
+		return die_("during grabbag__file_change_stats()");
+
+	return true;
+}
+
+static FLAC__bool remove_file_(const char *filename)
+{
+	while(our_metadata_.num_blocks > 0)
+		delete_from_our_metadata_(0);
+
+	if(!grabbag__file_remove_file(filename))
+		return die_("removing file");
+
+	return true;
+}
+
+static FLAC__bool test_level_0_(void)
+{
+	FLAC__StreamMetadata streaminfo;
+	FLAC__StreamMetadata *tags = 0;
+	FLAC__StreamMetadata *cuesheet = 0;
+	FLAC__StreamMetadata *picture = 0;
+
+	printf("\n\n++++++ testing level 0 interface\n");
+
+	if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
+		return false;
+
+	printf("testing FLAC__metadata_get_streaminfo()... ");
+
+	if(!FLAC__metadata_get_streaminfo(flacfilename(/*is_ogg=*/false), &streaminfo))
+		return die_("during FLAC__metadata_get_streaminfo()");
+
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(streaminfo.data.stream_info.channels != 1)
+		return die_("mismatch in streaminfo.data.stream_info.channels");
+	if(streaminfo.data.stream_info.bits_per_sample != 8)
+		return die_("mismatch in streaminfo.data.stream_info.bits_per_sample");
+	if(streaminfo.data.stream_info.sample_rate != 44100)
+		return die_("mismatch in streaminfo.data.stream_info.sample_rate");
+	if(streaminfo.data.stream_info.min_blocksize != 576)
+		return die_("mismatch in streaminfo.data.stream_info.min_blocksize");
+	if(streaminfo.data.stream_info.max_blocksize != 576)
+		return die_("mismatch in streaminfo.data.stream_info.max_blocksize");
+
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_get_tags()... ");
+
+	if(!FLAC__metadata_get_tags(flacfilename(/*is_ogg=*/false), &tags))
+		return die_("during FLAC__metadata_get_tags()");
+
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(tags->data.vorbis_comment.num_comments != 0)
+		return die_("mismatch in tags->data.vorbis_comment.num_comments");
+
+	printf("OK\n");
+
+	FLAC__metadata_object_delete(tags);
+
+	printf("testing FLAC__metadata_get_cuesheet()... ");
+
+	if(!FLAC__metadata_get_cuesheet(flacfilename(/*is_ogg=*/false), &cuesheet))
+		return die_("during FLAC__metadata_get_cuesheet()");
+
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(cuesheet->data.cue_sheet.lead_in != 123)
+		return die_("mismatch in cuesheet->data.cue_sheet.lead_in");
+
+	printf("OK\n");
+
+	FLAC__metadata_object_delete(cuesheet);
+
+	printf("testing FLAC__metadata_get_picture()... ");
+
+	if(!FLAC__metadata_get_picture(flacfilename(/*is_ogg=*/false), &picture, /*type=*/(FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-1)))
+		return die_("during FLAC__metadata_get_picture()");
+
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+		return die_("mismatch in picture->data.picture.type");
+
+	printf("OK\n");
+
+	FLAC__metadata_object_delete(picture);
+
+	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+		return false;
+
+	return true;
+}
+
+static FLAC__bool test_level_1_(void)
+{
+	FLAC__Metadata_SimpleIterator *iterator;
+	FLAC__StreamMetadata *block, *app, *padding;
+	FLAC__byte data[1000];
+	uint32_t our_current_position = 0;
+
+	/* initialize 'data' to avoid Valgrind errors */
+	memset(data, 0, sizeof(data));
+
+	printf("\n\n++++++ testing level 1 interface\n");
+
+	/************************************************************/
+
+	printf("simple iterator on read-only file\n");
+
+	if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
+		return false;
+
+	if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
+		return false;
+
+	if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
+		return die_("FLAC__metadata_simple_iterator_new()");
+
+	if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+		return die_("FLAC__metadata_simple_iterator_init() returned false");
+
+	printf("is writable = %u\n", (uint32_t)FLAC__metadata_simple_iterator_is_writable(iterator));
+	if(FLAC__metadata_simple_iterator_is_writable(iterator))
+		return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
+
+	printf("iterate forwards\n");
+
+	if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_STREAMINFO)
+		return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()");
+	if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
+		return die_("getting block 0");
+	if(block->type != FLAC__METADATA_TYPE_STREAMINFO)
+		return die_("expected STREAMINFO type");
+	if(block->is_last)
+		return die_("expected is_last to be false");
+	if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+		return die_("bad STREAMINFO length");
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(block->data.stream_info.channels != 1)
+		return die_("mismatch in channels");
+	if(block->data.stream_info.bits_per_sample != 8)
+		return die_("mismatch in bits_per_sample");
+	if(block->data.stream_info.sample_rate != 44100)
+		return die_("mismatch in sample_rate");
+	if(block->data.stream_info.min_blocksize != 576)
+		return die_("mismatch in min_blocksize");
+	if(block->data.stream_info.max_blocksize != 576)
+		return die_("mismatch in max_blocksize");
+	FLAC__metadata_object_delete(block);
+
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("forward iterator ended early");
+	our_current_position++;
+
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("forward iterator ended early");
+	our_current_position++;
+
+	if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_PADDING)
+		return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()");
+	if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
+		return die_("getting block 2");
+	if(block->type != FLAC__METADATA_TYPE_PADDING)
+		return die_("expected PADDING type");
+	if(!block->is_last)
+		return die_("expected is_last to be true");
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(block->length != 1234)
+		return die_("bad PADDING length");
+	FLAC__metadata_object_delete(block);
+
+	if(FLAC__metadata_simple_iterator_next(iterator))
+		return die_("forward iterator returned true but should have returned false");
+
+	printf("iterate backwards\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("reverse iterator ended early");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("reverse iterator ended early");
+	if(FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("reverse iterator returned true but should have returned false");
+
+	printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n");
+
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, (FLAC__StreamMetadata*)99, false))
+		printf("OK: FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
+	else
+		return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
+
+	FLAC__metadata_simple_iterator_delete(iterator);
+
+	/************************************************************/
+
+	printf("simple iterator on writable file\n");
+
+	if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
+		return false;
+
+	printf("creating APPLICATION block\n");
+
+	if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
+		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
+	memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+
+	printf("creating PADDING block\n");
+
+	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)");
+	padding->length = 20;
+
+	if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
+		return die_("FLAC__metadata_simple_iterator_new()");
+
+	if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+		return die_("FLAC__metadata_simple_iterator_init() returned false");
+	our_current_position = 0;
+
+	printf("is writable = %u\n", (uint32_t)FLAC__metadata_simple_iterator_is_writable(iterator));
+
+	printf("[S]VP\ttry to write over STREAMINFO block...\n");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
+		printf("\tFLAC__metadata_simple_iterator_set_block() returned false like it should\n");
+	else
+		return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
+
+	printf("[S]VP\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]P\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
+	padding->length = 25;
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	printf("SVP[P]\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SV[P]P\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
+	padding->length = 30;
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[P]PP\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]PPP\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
+	if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("[S]VPPP\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]PPP\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]PP\tdelete (middle block), replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
+	our_current_position--;
+
+	printf("S[V]PPP\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("S[V]PP\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]P\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVP[P]\tdelete (last block), replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	our_current_position--;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[P]P\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVP[P]\tdelete (last block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[P]\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]P\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("[S]VP\tset STREAMINFO (change sample rate)\n");
+	FLAC__ASSERT(our_current_position == 0);
+	block = FLAC__metadata_simple_iterator_get_block(iterator);
+	block->data.stream_info.sample_rate = 32000;
+	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
+	FLAC__metadata_object_delete(block);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("[S]VP\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
+	app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return false;
+	our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]P\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
+	app->data.application.id[0] = 'f'; /* twiddle the id */
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+	if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
+		return false;
+	our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
+	app->data.application.id[0] = 'g'; /* twiddle the id */
+	if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
+	app->data.application.id[0] = 'h'; /* twiddle the id */
+	if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
+	app->data.application.id[0] = 'i'; /* twiddle the id */
+	if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
+	app->data.application.id[0] = 'j'; /* twiddle the id */
+	if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
+		return die_("copying object");
+	our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVA[A]PP\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVAA[P]P\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
+	padding->length = 5;
+	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVAAP[P]\tset APPLICATION (grow)\n");
+	app->data.application.id[0] = 'k'; /* twiddle the id */
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVAAP[A]\tset PADDING (equal)\n");
+	padding->length = 27;
+	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVAAP[P]\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]P\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVA[P]\tinsert PADDING after\n");
+	padding->length = 5;
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVAP[P]\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SVA[P]P\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	our_metadata_.blocks[our_current_position+1]->length = 0;
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	our_metadata_.blocks[our_current_position]->is_last = true;
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]\tset PADDING (equal size)\n");
+	padding->length = app->length;
+	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true))
+		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[P]\tinsert PADDING after\n");
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVP[P]\tinsert PADDING after\n");
+	padding->length = 5;
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return false;
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVPP[P]\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SVP[P]P\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("SV[P]PP\tprev\n");
+	if(!FLAC__metadata_simple_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	our_metadata_.blocks[our_current_position+1]->length = 0;
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("S[V]PP\tnext\n");
+	if(!FLAC__metadata_simple_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
+	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+	delete_from_our_metadata_(our_current_position--);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+	if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
+		return die_("setting APPLICATION data");
+	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("delete simple iterator\n");
+
+	FLAC__metadata_simple_iterator_delete(iterator);
+
+	FLAC__metadata_object_delete(app);
+	FLAC__metadata_object_delete(padding);
+
+	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+		return false;
+
+	return true;
+}
+
+static FLAC__bool test_level_2_(FLAC__bool filename_based, FLAC__bool is_ogg)
+{
+	FLAC__Metadata_Iterator *iterator;
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block, *app, *padding;
+	FLAC__byte data[2000];
+	uint32_t our_current_position;
+
+	/* initialize 'data' to avoid Valgrind errors */
+	memset(data, 0, sizeof(data));
+
+	printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
+
+	printf("generate read-only file\n");
+
+	if(!generate_file_(/*include_extras=*/false, is_ogg))
+		return false;
+
+	if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
+		return false;
+
+	printf("create chain\n");
+
+	if(0 == (chain = FLAC__metadata_chain_new()))
+		return die_("allocating chain");
+
+	printf("read chain\n");
+
+	if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
+		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+	printf("[S]VP\ttest initial metadata\n");
+
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	if(is_ogg)
+		goto end;
+
+	printf("switch file to read-write\n");
+
+	if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
+		return false;
+
+	printf("create iterator\n");
+	if(0 == (iterator = FLAC__metadata_iterator_new()))
+		return die_("allocating memory for iterator");
+
+	our_current_position = 0;
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
+		return die_("getting block from iterator");
+
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+	printf("[S]VP\tmodify STREAMINFO, write\n");
+
+	block->data.stream_info.sample_rate = 32000;
+	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+		return die_("copying object");
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("[S]VP\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]P\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
+	if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
+		return die_("getting block from iterator");
+	if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
+		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
+	memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+	if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]\tshrink APPLICATION, don't use padding\n");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]\tgrow APPLICATION, don't use padding\n");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
+	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+		return die_("creating PADDING block");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	padding->length = 0;
+	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
+		return die_("internal error");
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	our_metadata_.blocks[our_current_position+1]->length = 13;
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
+	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("copying object");
+	if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
+		return die_("setting APPLICATION data");
+	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+		return die_("copying object");
+	delete_from_our_metadata_(our_current_position+1);
+	if(!FLAC__metadata_iterator_set_block(iterator, app))
+		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV[A]\tprev\n");
+	if(!FLAC__metadata_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("S[V]A\tprev\n");
+	if(!FLAC__metadata_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
+	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+		return die_("creating PADDING block");
+	padding->length = 30;
+	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+		printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
+	else
+		return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
+
+	printf("[S]VP\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]A\tinsert PADDING after\n");
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
+		return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("SV[P]A\tinsert PADDING before\n");
+	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("creating PADDING block");
+	padding->length = 17;
+	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("SV[P]PA\tinsert PADDING before\n");
+	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+		return die_("creating PADDING block");
+	padding->length = 0;
+	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("SV[P]PPA\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVP[P]PA\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVPP[P]A\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SVPPP[A]\tinsert PADDING after\n");
+	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
+		return die_("creating PADDING block");
+	padding->length = 57;
+	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
+		return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("SVPPPA[P]\tinsert PADDING before\n");
+	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
+		return die_("creating PADDING block");
+	padding->length = 99;
+	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+		return die_("copying metadata");
+	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("delete iterator\n");
+	FLAC__metadata_iterator_delete(iterator);
+	our_current_position = 0;
+
+	printf("SVPPPAPP\tmerge padding\n");
+	FLAC__metadata_chain_merge_padding(chain);
+	our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
+	our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
+	our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
+	delete_from_our_metadata_(7);
+	delete_from_our_metadata_(4);
+	delete_from_our_metadata_(3);
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SVPAP\tsort padding\n");
+	FLAC__metadata_chain_sort_padding(chain);
+	our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
+	delete_from_our_metadata_(2);
+
+	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("create iterator\n");
+	if(0 == (iterator = FLAC__metadata_iterator_new()))
+		return die_("allocating memory for iterator");
+
+	our_current_position = 0;
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	printf("[S]VAP\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("S[V]AP\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[A]P\tdelete middle block, replace with padding\n");
+	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+		return die_("creating PADDING block");
+	padding->length = 71;
+	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+		return die_("copying object");
+	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
+		return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("S[V]PP\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]P\tdelete middle block, don't replace with padding\n");
+	delete_from_our_metadata_(our_current_position--);
+	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+		return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("S[V]P\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]\tdelete last block, replace with padding\n");
+	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+		return die_("creating PADDING block");
+	padding->length = 219;
+	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+		return die_("copying object");
+	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
+		return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("S[V]P\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+	our_current_position++;
+
+	printf("SV[P]\tdelete last block, don't replace with padding\n");
+	delete_from_our_metadata_(our_current_position--);
+	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+		return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("S[V]\tprev\n");
+	if(!FLAC__metadata_iterator_prev(iterator))
+		return die_("iterator ended early\n");
+	our_current_position--;
+
+	printf("[S]V\tdelete STREAMINFO block, should fail\n");
+	if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+		return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
+
+	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+		return false;
+
+	printf("delete iterator\n");
+	FLAC__metadata_iterator_delete(iterator);
+	our_current_position = 0;
+
+	printf("SV\tmerge padding\n");
+	FLAC__metadata_chain_merge_padding(chain);
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+	printf("SV\tsort padding\n");
+	FLAC__metadata_chain_sort_padding(chain);
+
+	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+	if(!compare_chain_(chain, 0, 0))
+		return false;
+	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+		return false;
+
+end:
+	printf("delete chain\n");
+
+	FLAC__metadata_chain_delete(chain);
+
+	if(!remove_file_(flacfilename(is_ogg)))
+		return false;
+
+	return true;
+}
+
+static FLAC__bool test_level_2_misc_(FLAC__bool is_ogg)
+{
+	FLAC__Metadata_Iterator *iterator;
+	FLAC__Metadata_Chain *chain;
+	FLAC__IOCallbacks callbacks;
+
+	memset(&callbacks, 0, sizeof(callbacks));
+	callbacks.read = (FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+	callbacks.write = chain_write_cb_;
+#else
+	callbacks.write = (FLAC__IOCallback_Write)fwrite;
+#endif
+	callbacks.seek = chain_seek_cb_;
+	callbacks.tell = chain_tell_cb_;
+	callbacks.eof = chain_eof_cb_;
+
+	printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
+
+	printf("generate file\n");
+
+	if(!generate_file_(/*include_extras=*/false, is_ogg))
+		return false;
+
+	printf("create chain\n");
+
+	if(0 == (chain = FLAC__metadata_chain_new()))
+		return die_("allocating chain");
+
+	printf("read chain (filename-based)\n");
+
+	if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
+		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
+	{
+		if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
+			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+		printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+	}
+
+	printf("read chain (filename-based)\n");
+
+	if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
+		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
+	{
+		if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
+			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+		printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+	}
+
+	printf("read chain (callback-based)\n");
+	{
+		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
+		if(0 == file)
+			return die_("opening file");
+		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+			fclose(file);
+			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+		}
+		fclose(file);
+	}
+
+	printf("write chain with wrong method FLAC__metadata_chain_write()\n");
+	{
+		if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+		printf("  OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+	}
+
+	printf("read chain (callback-based)\n");
+	{
+		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
+		if(0 == file)
+			return die_("opening file");
+		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+			fclose(file);
+			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+		}
+		fclose(file);
+	}
+
+	printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
+
+	if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
+		printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n");
+	else
+		return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have");
+
+	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
+	{
+		if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
+			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
+		printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+	}
+
+	printf("read chain (callback-based)\n");
+	{
+		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
+		if(0 == file)
+			return die_("opening file");
+		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+			fclose(file);
+			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+		}
+		fclose(file);
+	}
+
+	printf("create iterator\n");
+	if(0 == (iterator = FLAC__metadata_iterator_new()))
+		return die_("allocating memory for iterator");
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	printf("[S]VP\tnext\n");
+	if(!FLAC__metadata_iterator_next(iterator))
+		return die_("iterator ended early\n");
+
+	printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
+	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+		return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain));
+
+	printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
+
+	if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
+		printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n");
+	else
+		return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have");
+
+	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
+	{
+		if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
+			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
+		printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+	}
+
+	printf("delete iterator\n");
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	printf("delete chain\n");
+
+	FLAC__metadata_chain_delete(chain);
+
+	if(!remove_file_(flacfilename(is_ogg)))
+		return false;
+
+	return true;
+}
+
+FLAC__bool test_metadata_file_manipulation(void)
+{
+	printf("\n+++ libFLAC unit test: metadata manipulation\n\n");
+
+	our_metadata_.num_blocks = 0;
+
+	if(!test_level_0_())
+		return false;
+
+	if(!test_level_1_())
+		return false;
+
+	if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
+		return false;
+	if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
+		return false;
+	if(!test_level_2_misc_(/*is_ogg=*/false))
+		return false;
+
+	if(FLAC_API_SUPPORTS_OGG_FLAC) {
+		if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
+			return false;
+		if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
+			return false;
+#if 0
+		/* when ogg flac write is supported, will have to add this: */
+		if(!test_level_2_misc_(/*is_ogg=*/true))
+			return false;
+#endif
+	}
+
+	return true;
+}
diff --git a/src/test_libFLAC/metadata_object.c b/src/test_libFLAC/metadata_object.c
new file mode 100644
index 0000000..b52b923
--- /dev/null
+++ b/src/test_libFLAC/metadata_object.c
@@ -0,0 +1,2285 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "test_libs_common/metadata_utils.h"
+#include "share/compat.h"
+#include "metadata.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+
+static FLAC__byte *make_dummydata_(FLAC__byte *dummydata, uint32_t len)
+{
+	FLAC__byte *ret;
+
+	if(0 == (ret = malloc(len))) {
+		printf("FAILED, malloc error\n");
+		exit(1);
+	}
+	else
+		memcpy(ret, dummydata, len);
+
+	return ret;
+}
+
+static FLAC__bool compare_track_(const FLAC__StreamMetadata_CueSheet_Track *from, const FLAC__StreamMetadata_CueSheet_Track *to)
+{
+	uint32_t i;
+
+	if(from->offset != to->offset) {
+		printf("FAILED, track offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", to->offset, from->offset);
+		return false;
+	}
+	if(from->number != to->number) {
+		printf("FAILED, track number mismatch, expected %u, got %u\n", (uint32_t)to->number, (uint32_t)from->number);
+		return false;
+	}
+	if(0 != strcmp(from->isrc, to->isrc)) {
+		printf("FAILED, track number mismatch, expected %s, got %s\n", to->isrc, from->isrc);
+		return false;
+	}
+	if(from->type != to->type) {
+		printf("FAILED, track type mismatch, expected %u, got %u\n", (uint32_t)to->type, (uint32_t)from->type);
+		return false;
+	}
+	if(from->pre_emphasis != to->pre_emphasis) {
+		printf("FAILED, track pre_emphasis mismatch, expected %u, got %u\n", (uint32_t)to->pre_emphasis, (uint32_t)from->pre_emphasis);
+		return false;
+	}
+	if(from->num_indices != to->num_indices) {
+		printf("FAILED, track num_indices mismatch, expected %u, got %u\n", (uint32_t)to->num_indices, (uint32_t)from->num_indices);
+		return false;
+	}
+	if(0 == to->indices || 0 == from->indices) {
+		if(to->indices != from->indices) {
+			printf("FAILED, track indices mismatch\n");
+			return false;
+		}
+	}
+	else {
+		for(i = 0; i < to->num_indices; i++) {
+			if(from->indices[i].offset != to->indices[i].offset) {
+				printf("FAILED, track indices[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to->indices[i].offset, from->indices[i].offset);
+				return false;
+			}
+			if(from->indices[i].number != to->indices[i].number) {
+				printf("FAILED, track indices[%u].number mismatch, expected %u, got %u\n", i, (uint32_t)to->indices[i].number, (uint32_t)from->indices[i].number);
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+static FLAC__bool compare_seekpoint_array_(const FLAC__StreamMetadata_SeekPoint *from, const FLAC__StreamMetadata_SeekPoint *to, uint32_t n)
+{
+	uint32_t i;
+
+	FLAC__ASSERT(0 != from);
+	FLAC__ASSERT(0 != to);
+
+	for(i = 0; i < n; i++) {
+		if(from[i].sample_number != to[i].sample_number) {
+			printf("FAILED, point[%u].sample_number mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to[i].sample_number, from[i].sample_number);
+			return false;
+		}
+		if(from[i].stream_offset != to[i].stream_offset) {
+			printf("FAILED, point[%u].stream_offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to[i].stream_offset, from[i].stream_offset);
+			return false;
+		}
+		if(from[i].frame_samples != to[i].frame_samples) {
+			printf("FAILED, point[%u].frame_samples mismatch, expected %u, got %u\n", i, to[i].frame_samples, from[i].frame_samples);
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static FLAC__bool check_seektable_(const FLAC__StreamMetadata *block, uint32_t num_points, const FLAC__StreamMetadata_SeekPoint *array)
+{
+	const uint32_t expected_length = num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	if(block->data.seek_table.num_points != num_points) {
+		printf("FAILED, expected %u point, got %u\n", num_points, block->data.seek_table.num_points);
+		return false;
+	}
+	if(0 == array) {
+		if(0 != block->data.seek_table.points) {
+			printf("FAILED, 'points' pointer is not null\n");
+			return false;
+		}
+	}
+	else {
+		if(!compare_seekpoint_array_(block->data.seek_table.points, array, num_points))
+			return false;
+	}
+	printf("OK\n");
+
+	return true;
+}
+
+static void entry_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field)
+{
+	entry->length = strlen(field);
+	entry->entry = malloc(entry->length+1);
+	FLAC__ASSERT(0 != entry->entry);
+	memcpy(entry->entry, field, entry->length);
+	entry->entry[entry->length] = '\0';
+}
+
+static void entry_clone_(FLAC__StreamMetadata_VorbisComment_Entry *entry)
+{
+	FLAC__byte *x = malloc(entry->length+1);
+	FLAC__ASSERT(0 != x);
+	memcpy(x, entry->entry, entry->length);
+	x[entry->length] = '\0';
+	entry->entry = x;
+}
+
+static void vc_calc_len_(FLAC__StreamMetadata *block)
+{
+	const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
+	uint32_t i;
+
+	block->length = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+	block->length += vc->vendor_string.length;
+	block->length += FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+	for(i = 0; i < vc->num_comments; i++) {
+		block->length += FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+		block->length += vc->comments[i].length;
+	}
+}
+
+static void vc_resize_(FLAC__StreamMetadata *block, uint32_t num)
+{
+	FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
+
+	if(vc->num_comments != 0) {
+		FLAC__ASSERT(0 != vc->comments);
+		if(num < vc->num_comments) {
+			uint32_t i;
+			for(i = num; i < vc->num_comments; i++) {
+				if(0 != vc->comments[i].entry)
+					free(vc->comments[i].entry);
+			}
+		}
+	}
+	if(num == 0) {
+		if(0 != vc->comments) {
+			free(vc->comments);
+			vc->comments = 0;
+		}
+	}
+	else {
+		vc->comments = realloc(vc->comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*num);
+		FLAC__ASSERT(0 != vc->comments);
+		if(num > vc->num_comments)
+			memset(vc->comments+vc->num_comments, 0, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(num-vc->num_comments));
+	}
+
+	vc->num_comments = num;
+	vc_calc_len_(block);
+}
+
+static int vc_find_from_(FLAC__StreamMetadata *block, const char *name, uint32_t start)
+{
+	const uint32_t n = strlen(name);
+	uint32_t i;
+	for(i = start; i < block->data.vorbis_comment.num_comments; i++) {
+		const FLAC__StreamMetadata_VorbisComment_Entry *entry = &block->data.vorbis_comment.comments[i];
+		if(entry->length > n && 0 == strncmp((const char *)entry->entry, name, n) && entry->entry[n] == '=')
+			return (int)i;
+	}
+	return -1;
+}
+
+static void vc_set_vs_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field)
+{
+	if(0 != block->data.vorbis_comment.vendor_string.entry)
+		free(block->data.vorbis_comment.vendor_string.entry);
+	entry_new_(entry, field);
+	block->data.vorbis_comment.vendor_string = *entry;
+	vc_calc_len_(block);
+}
+
+static void vc_set_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, uint32_t pos, const char *field)
+{
+	if(0 != block->data.vorbis_comment.comments[pos].entry)
+		free(block->data.vorbis_comment.comments[pos].entry);
+	entry_new_(entry, field);
+	block->data.vorbis_comment.comments[pos] = *entry;
+	vc_calc_len_(block);
+}
+
+static void vc_insert_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, uint32_t pos, const char *field)
+{
+	vc_resize_(block, block->data.vorbis_comment.num_comments+1);
+	memmove(&block->data.vorbis_comment.comments[pos+1], &block->data.vorbis_comment.comments[pos], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(block->data.vorbis_comment.num_comments-1-pos));
+	memset(&block->data.vorbis_comment.comments[pos], 0, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+	vc_set_new_(entry, block, pos, field);
+	vc_calc_len_(block);
+}
+
+static void vc_delete_(FLAC__StreamMetadata *block, uint32_t pos)
+{
+	if(0 != block->data.vorbis_comment.comments[pos].entry)
+		free(block->data.vorbis_comment.comments[pos].entry);
+	memmove(&block->data.vorbis_comment.comments[pos], &block->data.vorbis_comment.comments[pos+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(block->data.vorbis_comment.num_comments-pos-1));
+	block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1].entry = 0;
+	block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1].length = 0;
+	vc_resize_(block, block->data.vorbis_comment.num_comments-1);
+	vc_calc_len_(block);
+}
+
+static void vc_replace_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field, FLAC__bool all)
+{
+	int indx;
+	char field_name[256];
+	const char *eq = strchr(field, '=');
+	FLAC__ASSERT(eq>field && (uint32_t)(eq-field) < sizeof(field_name));
+	memcpy(field_name, field, eq-field);
+	field_name[eq-field]='\0';
+
+	indx = vc_find_from_(block, field_name, 0);
+	if(indx < 0)
+		vc_insert_new_(entry, block, block->data.vorbis_comment.num_comments, field);
+	else {
+		vc_set_new_(entry, block, (uint32_t)indx, field);
+		if(all) {
+			for(indx = indx+1; indx >= 0 && (uint32_t)indx < block->data.vorbis_comment.num_comments; )
+				if((indx = vc_find_from_(block, field_name, (uint32_t)indx)) >= 0)
+					vc_delete_(block, (uint32_t)indx);
+		}
+	}
+
+	vc_calc_len_(block);
+}
+
+static void track_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+	track->offset = offset;
+	track->number = number;
+	memcpy(track->isrc, isrc, sizeof(track->isrc));
+	track->type = data;
+	track->pre_emphasis = pre_em;
+	track->num_indices = 0;
+	track->indices = 0;
+}
+
+static void track_clone_(FLAC__StreamMetadata_CueSheet_Track *track)
+{
+	if(track->num_indices > 0) {
+		size_t bytes = sizeof(FLAC__StreamMetadata_CueSheet_Index) * track->num_indices;
+		FLAC__StreamMetadata_CueSheet_Index *x = malloc(bytes);
+		FLAC__ASSERT(0 != x);
+		memcpy(x, track->indices, bytes);
+		track->indices = x;
+	}
+}
+
+static void cs_calc_len_(FLAC__StreamMetadata *block)
+{
+	const FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+	uint32_t i;
+
+	block->length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+	block->length += cs->num_tracks * (
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+	) / 8;
+	for(i = 0; i < cs->num_tracks; i++) {
+		block->length += cs->tracks[i].num_indices * (
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+		) / 8;
+	}
+}
+
+static void tr_resize_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t num)
+{
+	FLAC__StreamMetadata_CueSheet_Track *tr;
+
+	FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+	tr = &block->data.cue_sheet.tracks[track_num];
+
+	if(tr->num_indices != 0) {
+		FLAC__ASSERT(0 != tr->indices);
+	}
+	if(num == 0) {
+		if(0 != tr->indices) {
+			free(tr->indices);
+			tr->indices = 0;
+		}
+	}
+	else {
+		tr->indices = realloc(tr->indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)*num);
+		FLAC__ASSERT(0 != tr->indices);
+		if(num > tr->num_indices)
+			memset(tr->indices+tr->num_indices, 0, sizeof(FLAC__StreamMetadata_CueSheet_Index)*(num-tr->num_indices));
+	}
+
+	tr->num_indices = num;
+	cs_calc_len_(block);
+}
+
+static void tr_set_new_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t pos, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+	FLAC__StreamMetadata_CueSheet_Track *tr;
+
+	FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+	tr = &block->data.cue_sheet.tracks[track_num];
+
+	FLAC__ASSERT(pos < tr->num_indices);
+
+	tr->indices[pos] = indx;
+
+	cs_calc_len_(block);
+}
+
+static void tr_insert_new_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t pos, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+	FLAC__StreamMetadata_CueSheet_Track *tr;
+
+	FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+	tr = &block->data.cue_sheet.tracks[track_num];
+
+	FLAC__ASSERT(pos <= tr->num_indices);
+
+	tr_resize_(block, track_num, tr->num_indices+1);
+	memmove(&tr->indices[pos+1], &tr->indices[pos], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(tr->num_indices-1-pos));
+	tr_set_new_(block, track_num, pos, indx);
+	cs_calc_len_(block);
+}
+
+static void tr_delete_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t pos)
+{
+	FLAC__StreamMetadata_CueSheet_Track *tr;
+
+	FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+	tr = &block->data.cue_sheet.tracks[track_num];
+
+	FLAC__ASSERT(pos <= tr->num_indices);
+
+	memmove(&tr->indices[pos], &tr->indices[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(tr->num_indices-pos-1));
+	tr_resize_(block, track_num, tr->num_indices-1);
+	cs_calc_len_(block);
+}
+
+static void cs_resize_(FLAC__StreamMetadata *block, uint32_t num)
+{
+	FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+
+	if(cs->num_tracks != 0) {
+		FLAC__ASSERT(0 != cs->tracks);
+		if(num < cs->num_tracks) {
+			uint32_t i;
+			for(i = num; i < cs->num_tracks; i++) {
+				if(0 != cs->tracks[i].indices)
+					free(cs->tracks[i].indices);
+			}
+		}
+	}
+	if(num == 0) {
+		if(0 != cs->tracks) {
+			free(cs->tracks);
+			cs->tracks = 0;
+		}
+	}
+	else {
+		cs->tracks = realloc(cs->tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)*num);
+		FLAC__ASSERT(0 != cs->tracks);
+		if(num > cs->num_tracks)
+			memset(cs->tracks+cs->num_tracks, 0, sizeof(FLAC__StreamMetadata_CueSheet_Track)*(num-cs->num_tracks));
+	}
+
+	cs->num_tracks = num;
+	cs_calc_len_(block);
+}
+
+static void cs_set_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, uint32_t pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+	track_new_(track, offset, number, isrc, data, pre_em);
+	block->data.cue_sheet.tracks[pos] = *track;
+	cs_calc_len_(block);
+}
+
+static void cs_insert_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, uint32_t pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+	cs_resize_(block, block->data.cue_sheet.num_tracks+1);
+	memmove(&block->data.cue_sheet.tracks[pos+1], &block->data.cue_sheet.tracks[pos], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-1-pos));
+	cs_set_new_(track, block, pos, offset, number, isrc, data, pre_em);
+	cs_calc_len_(block);
+}
+
+static void cs_delete_(FLAC__StreamMetadata *block, uint32_t pos)
+{
+	if(0 != block->data.cue_sheet.tracks[pos].indices)
+		free(block->data.cue_sheet.tracks[pos].indices);
+	memmove(&block->data.cue_sheet.tracks[pos], &block->data.cue_sheet.tracks[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-pos-1));
+	block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].indices = 0;
+	block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].num_indices = 0;
+	cs_resize_(block, block->data.cue_sheet.num_tracks-1);
+	cs_calc_len_(block);
+}
+
+static void pi_set_mime_type(FLAC__StreamMetadata *block, const char *s)
+{
+	if(block->data.picture.mime_type) {
+		block->length -= strlen(block->data.picture.mime_type);
+		free(block->data.picture.mime_type);
+	}
+	block->data.picture.mime_type = strdup(s);
+	FLAC__ASSERT(block->data.picture.mime_type);
+	block->length += strlen(block->data.picture.mime_type);
+}
+
+static void pi_set_description(FLAC__StreamMetadata *block, const FLAC__byte *s)
+{
+	if(block->data.picture.description) {
+		block->length -= strlen((const char *)block->data.picture.description);
+		free(block->data.picture.description);
+	}
+	block->data.picture.description = (FLAC__byte*)strdup((const char *)s);
+	FLAC__ASSERT(block->data.picture.description);
+	block->length += strlen((const char *)block->data.picture.description);
+}
+
+static void pi_set_data(FLAC__StreamMetadata *block, const FLAC__byte *data, FLAC__uint32 len)
+{
+	if(block->data.picture.data) {
+		block->length -= block->data.picture.data_length;
+		free(block->data.picture.data);
+	}
+	block->data.picture.data = (FLAC__byte*)strdup((const char *)data);
+	FLAC__ASSERT(block->data.picture.data);
+	block->data.picture.data_length = len;
+	block->length += len;
+}
+
+FLAC__bool test_metadata_object(void)
+{
+	FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet, *picture;
+	FLAC__StreamMetadata_SeekPoint seekpoint_array[14];
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+	FLAC__StreamMetadata_CueSheet_Index indx;
+	FLAC__StreamMetadata_CueSheet_Track track;
+	uint32_t i, expected_length, seekpoints;
+	int j;
+	static FLAC__byte dummydata[4] = { 'a', 'b', 'c', 'd' };
+
+	printf("\n+++ libFLAC unit test: metadata objects\n\n");
+
+
+	printf("testing STREAMINFO\n");
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	expected_length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing PADDING\n");
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	expected_length = 0;
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing APPLICATION\n");
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	expected_length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_application_set_data(copy)... ");
+	if(!FLAC__metadata_object_application_set_data(block, dummydata, sizeof(dummydata), true/*copy*/)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	expected_length = (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) + sizeof(dummydata);
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	if(0 != memcmp(block->data.application.data, dummydata, sizeof(dummydata))) {
+		printf("FAILED, data mismatch\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_application_set_data(own)... ");
+	if(!FLAC__metadata_object_application_set_data(block, make_dummydata_(dummydata, sizeof(dummydata)), sizeof(dummydata), false/*own*/)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	expected_length = (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) + sizeof(dummydata);
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	if(0 != memcmp(block->data.application.data, dummydata, sizeof(dummydata))) {
+		printf("FAILED, data mismatch\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing SEEKTABLE\n");
+
+	for(i = 0; i < sizeof(seekpoint_array) / sizeof(FLAC__StreamMetadata_SeekPoint); i++) {
+		seekpoint_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+		seekpoint_array[i].stream_offset = 0;
+		seekpoint_array[i].frame_samples = 0;
+	}
+
+	seekpoints = 0;
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, 0))
+		return false;
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	seekpoints = 2;
+	printf("testing FLAC__metadata_object_seektable_resize_points(grow to %u)...", seekpoints);
+	if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoints = 1;
+	printf("testing FLAC__metadata_object_seektable_resize_points(shrink to %u)...", seekpoints);
+	if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	printf("testing FLAC__metadata_object_seektable_is_legal()...");
+	if(!FLAC__metadata_object_seektable_is_legal(block)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	printf("OK\n");
+
+	seekpoints = 0;
+	printf("testing FLAC__metadata_object_seektable_resize_points(shrink to %u)...", seekpoints);
+	if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, 0))
+		return false;
+
+	seekpoints++;
+	printf("testing FLAC__metadata_object_seektable_insert_point() on empty array...");
+	if(!FLAC__metadata_object_seektable_insert_point(block, 0, seekpoint_array[0])) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoint_array[0].sample_number = 1;
+	seekpoints++;
+	printf("testing FLAC__metadata_object_seektable_insert_point() on beginning of non-empty array...");
+	if(!FLAC__metadata_object_seektable_insert_point(block, 0, seekpoint_array[0])) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoint_array[1].sample_number = 2;
+	seekpoints++;
+	printf("testing FLAC__metadata_object_seektable_insert_point() on middle of non-empty array...");
+	if(!FLAC__metadata_object_seektable_insert_point(block, 1, seekpoint_array[1])) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoint_array[3].sample_number = 3;
+	seekpoints++;
+	printf("testing FLAC__metadata_object_seektable_insert_point() on end of non-empty array...");
+	if(!FLAC__metadata_object_seektable_insert_point(block, 3, seekpoint_array[3])) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	seekpoint_array[2].sample_number = seekpoint_array[3].sample_number;
+	seekpoints--;
+	printf("testing FLAC__metadata_object_seektable_delete_point() on middle of array...");
+	if(!FLAC__metadata_object_seektable_delete_point(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoints--;
+	printf("testing FLAC__metadata_object_seektable_delete_point() on end of array...");
+	if(!FLAC__metadata_object_seektable_delete_point(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoints--;
+	printf("testing FLAC__metadata_object_seektable_delete_point() on beginning of array...");
+	if(!FLAC__metadata_object_seektable_delete_point(block, 0)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array+1))
+		return false;
+
+	printf("testing FLAC__metadata_object_seektable_set_point()...");
+	FLAC__metadata_object_seektable_set_point(block, 0, seekpoint_array[0]);
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+	/* seektable template functions */
+
+	for(i = 0; i < sizeof(seekpoint_array) / sizeof(FLAC__StreamMetadata_SeekPoint); i++) {
+		seekpoint_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+		seekpoint_array[i].stream_offset = 0;
+		seekpoint_array[i].frame_samples = 0;
+	}
+
+	seekpoints = 0;
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, 0))
+		return false;
+
+	seekpoints += 2;
+	printf("testing FLAC__metadata_object_seekpoint_template_append_placeholders()... ");
+	if(!FLAC__metadata_object_seektable_template_append_placeholders(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoint_array[seekpoints++].sample_number = 7;
+	printf("testing FLAC__metadata_object_seekpoint_template_append_point()... ");
+	if(!FLAC__metadata_object_seektable_template_append_point(block, 7)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	{
+		FLAC__uint64 nums[2] = { 3, 7 };
+		seekpoint_array[seekpoints++].sample_number = nums[0];
+		seekpoint_array[seekpoints++].sample_number = nums[1];
+		printf("testing FLAC__metadata_object_seekpoint_template_append_points()... ");
+		if(!FLAC__metadata_object_seektable_template_append_points(block, nums, sizeof(nums)/sizeof(FLAC__uint64))) {
+			printf("FAILED, returned false\n");
+			return false;
+		}
+		if(!check_seektable_(block, seekpoints, seekpoint_array))
+			return false;
+	}
+
+	seekpoint_array[seekpoints++].sample_number = 0;
+	seekpoint_array[seekpoints++].sample_number = 10;
+	seekpoint_array[seekpoints++].sample_number = 20;
+	printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points()... ");
+	if(!FLAC__metadata_object_seektable_template_append_spaced_points(block, 3, 30)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoints--;
+	seekpoint_array[0].sample_number = 0;
+	seekpoint_array[1].sample_number = 3;
+	seekpoint_array[2].sample_number = 7;
+	seekpoint_array[3].sample_number = 10;
+	seekpoint_array[4].sample_number = 20;
+	seekpoint_array[5].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+	seekpoint_array[6].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+	printf("testing FLAC__metadata_object_seekpoint_template_sort(compact=true)... ");
+	if(!FLAC__metadata_object_seektable_template_sort(block, /*compact=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!FLAC__metadata_object_seektable_is_legal(block)) {
+		printf("FAILED, seek table is illegal\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	printf("testing FLAC__metadata_object_seekpoint_template_sort(compact=false)... ");
+	if(!FLAC__metadata_object_seektable_template_sort(block, /*compact=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!FLAC__metadata_object_seektable_is_legal(block)) {
+		printf("FAILED, seek table is illegal\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoint_array[seekpoints++].sample_number = 0;
+	seekpoint_array[seekpoints++].sample_number = 10;
+	seekpoint_array[seekpoints++].sample_number = 20;
+	printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points_by_samples()... ");
+	if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(block, 10, 30)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	seekpoint_array[seekpoints++].sample_number = 0;
+	seekpoint_array[seekpoints++].sample_number = 11;
+	seekpoint_array[seekpoints++].sample_number = 22;
+	printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points_by_samples()... ");
+	if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(block, 11, 30)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!check_seektable_(block, seekpoints, seekpoint_array))
+		return false;
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing VORBIS_COMMENT\n");
+
+	{
+		FLAC__StreamMetadata_VorbisComment_Entry entry_;
+		char *field_name, *field_value;
+
+		printf("testing FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair()... ");
+		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry_, "name", "value")) {
+			printf("FAILED, returned false\n");
+			return false;
+		}
+		if(strcmp((const char *)entry_.entry, "name=value")) {
+			printf("FAILED, field mismatch\n");
+			return false;
+		}
+		printf("OK\n");
+
+		printf("testing FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair()... ");
+		if(!FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(entry_, &field_name, &field_value)) {
+			printf("FAILED, returned false\n");
+			return false;
+		}
+		if(strcmp(field_name, "name")) {
+			printf("FAILED, field name mismatch\n");
+			return false;
+		}
+		if(strcmp(field_value, "value")) {
+			printf("FAILED, field value mismatch\n");
+			return false;
+		}
+		printf("OK\n");
+
+		printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... ");
+		if(!FLAC__metadata_object_vorbiscomment_entry_matches(entry_, field_name, strlen(field_name))) {
+			printf("FAILED, expected true, returned false\n");
+			return false;
+		}
+		printf("OK\n");
+
+		printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... ");
+		if(FLAC__metadata_object_vorbiscomment_entry_matches(entry_, "blah", strlen("blah"))) {
+			printf("FAILED, expected false, returned true\n");
+			return false;
+		}
+		printf("OK\n");
+
+		free(entry_.entry);
+		free(field_name);
+		free(field_value);
+	}
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	expected_length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + strlen(FLAC__VENDOR_STRING) + FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8);
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	vorbiscomment = FLAC__metadata_object_clone(block);
+	if(0 == vorbiscomment) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	vc_resize_(vorbiscomment, 2);
+	printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(grow to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+	if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	vc_resize_(vorbiscomment, 1);
+	printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+	if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	vc_resize_(vorbiscomment, 0);
+	printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+	if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+	if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2");
+	if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	vc_resize_(vorbiscomment, 0);
+	printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+	if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on beginning of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 0, "name2=field2");
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on middle of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 1, "name3=field3");
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 1, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 3, "name4=field4");
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 3, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1");
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1");
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+	if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name3")) != 1) {
+		printf("FAILED, expected 1, got %d\n", j);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+	if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 4) {
+		printf("FAILED, expected 4, got %d\n", j);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+	if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 5) {
+		printf("FAILED, expected 5, got %d\n", j);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+	if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name2")) != 0) {
+		printf("FAILED, expected 0, got %d\n", j);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+	if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name2")) != -1) {
+		printf("FAILED, expected -1, got %d\n", j);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+	if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "blah")) != -1) {
+		printf("FAILED, expected -1, got %d\n", j);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, copy)...");
+	vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false);
+	if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	if(block->data.vorbis_comment.num_comments != 6) {
+		printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, copy)...");
+	vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true);
+	if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	if(block->data.vorbis_comment.num_comments != 4) {
+		printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array...");
+	vc_delete_(vorbiscomment, 2);
+	if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on end of array...");
+	vc_delete_(vorbiscomment, 2);
+	if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on beginning of array...");
+	vc_delete_(vorbiscomment, 0);
+	if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 0)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 1, "rem0=val0");
+	if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 2, "rem0=val1");
+	if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 3, "rem0=val2");
+	if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"blah\")...");
+	if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "blah")) != 0) {
+		printf("FAILED, expected 0, got %d\n", j);
+		return false;
+	}
+	if(block->data.vorbis_comment.num_comments != 4) {
+		printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"rem0\")...");
+	vc_delete_(vorbiscomment, 1);
+	if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "rem0")) != 1) {
+		printf("FAILED, expected 1, got %d\n", j);
+		return false;
+	}
+	if(block->data.vorbis_comment.num_comments != 3) {
+		printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments);
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"blah\")...");
+	if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "blah")) != 0) {
+		printf("FAILED, expected 0, got %d\n", j);
+		return false;
+	}
+	if(block->data.vorbis_comment.num_comments != 3) {
+		printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments);
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"rem0\")...");
+	vc_delete_(vorbiscomment, 1);
+	vc_delete_(vorbiscomment, 1);
+	if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "rem0")) != 2) {
+		printf("FAILED, expected 2, got %d\n", j);
+		return false;
+	}
+	if(block->data.vorbis_comment.num_comments != 1) {
+		printf("FAILED, expected 1 comments, got %u\n", block->data.vorbis_comment.num_comments);
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_set_comment(copy)...");
+	vc_set_new_(&entry, vorbiscomment, 0, "name5=field5");
+	FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/true);
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_set_vendor_string(copy)...");
+	vc_set_vs_new_(&entry, vorbiscomment, "name6=field6");
+	FLAC__metadata_object_vorbiscomment_set_vendor_string(block, entry, /*copy=*/true);
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(vorbiscomment);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	vorbiscomment = FLAC__metadata_object_clone(block);
+	if(0 == vorbiscomment) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2");
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(vorbiscomment);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	vorbiscomment = FLAC__metadata_object_clone(block);
+	if(0 == vorbiscomment) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on beginning of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 0, "name2=field2");
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on middle of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 1, "name3=field3");
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 1, entry, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 3, "name4=field4");
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 3, entry, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1");
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+	vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1");
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, own)...");
+	vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false);
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	if(block->data.vorbis_comment.num_comments != 6) {
+		printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, own)...");
+	vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true);
+	entry_clone_(&entry);
+	if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	if(block->data.vorbis_comment.num_comments != 4) {
+		printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array...");
+	vc_delete_(vorbiscomment, 2);
+	if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on end of array...");
+	vc_delete_(vorbiscomment, 2);
+	if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on beginning of array...");
+	vc_delete_(vorbiscomment, 0);
+	if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 0)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_set_comment(own)...");
+	vc_set_new_(&entry, vorbiscomment, 0, "name5=field5");
+	entry_clone_(&entry);
+	FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/false);
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_vorbiscomment_set_vendor_string(own)...");
+	vc_set_vs_new_(&entry, vorbiscomment, "name6=field6");
+	entry_clone_(&entry);
+	FLAC__metadata_object_vorbiscomment_set_vendor_string(block, entry, /*copy=*/false);
+	if(!mutils__compare_block(vorbiscomment, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(vorbiscomment);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing CUESHEET\n");
+
+	{
+		FLAC__StreamMetadata_CueSheet_Track *track_, *trackcopy_;
+
+		printf("testing FLAC__metadata_object_cuesheet_track_new()... ");
+		track_ = FLAC__metadata_object_cuesheet_track_new();
+		if(0 == track_) {
+			printf("FAILED, returned NULL\n");
+			return false;
+		}
+		printf("OK\n");
+
+		printf("testing FLAC__metadata_object_cuesheet_track_clone()... ");
+		trackcopy_ = FLAC__metadata_object_cuesheet_track_clone(track_);
+		if(0 == trackcopy_) {
+			printf("FAILED, returned NULL\n");
+			return false;
+		}
+		if(!compare_track_(trackcopy_, track_))
+			return false;
+		printf("OK\n");
+
+		printf("testing FLAC__metadata_object_cuesheet_track_delete()... ");
+		FLAC__metadata_object_cuesheet_track_delete(trackcopy_);
+		FLAC__metadata_object_cuesheet_track_delete(track_);
+		printf("OK\n");
+	}
+
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	expected_length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	cuesheet = FLAC__metadata_object_clone(block);
+	if(0 == cuesheet) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	cs_resize_(cuesheet, 2);
+	printf("testing FLAC__metadata_object_cuesheet_resize_tracks(grow to %u)...", cuesheet->data.cue_sheet.num_tracks);
+	if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	cs_resize_(cuesheet, 1);
+	printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks);
+	if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	cs_resize_(cuesheet, 0);
+	printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks);
+	if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on empty array...");
+	cs_insert_new_(&track, cuesheet, 0, 0, 1, "ABCDE1234567", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on beginning of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 0, 10, 2, "BBCDE1234567", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on middle of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 1, 20, 3, "CBCDE1234567", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, &track, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on end of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 3, 30, 4, "DBCDE1234567", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, &track, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_blank_track() on end of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 4, 0, 0, "\0\0\0\0\0\0\0\0\0\0\0\0", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_blank_track(block, 4)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+	cs_delete_(cuesheet, 4);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 4)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array...");
+	cs_delete_(cuesheet, 2);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+	cs_delete_(cuesheet, 2);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array...");
+	cs_delete_(cuesheet, 0);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_set_track(copy)...");
+	cs_set_new_(&track, cuesheet, 0, 40, 5, "EBCDE1234567", false, false);
+	FLAC__metadata_object_cuesheet_set_track(block, 0, &track, /*copy=*/true);
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	tr_resize_(cuesheet, 0, 2);
+	printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(grow to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+	if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	tr_resize_(cuesheet, 0, 1);
+	printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(shrink to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+	if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	tr_resize_(cuesheet, 0, 0);
+	printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(shrink to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+	if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	indx.offset = 0;
+	indx.number = 1;
+	printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on empty array...");
+	tr_insert_new_(cuesheet, 0, 0, indx);
+	if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, indx)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	indx.offset = 10;
+	indx.number = 2;
+	printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on beginning of non-empty array...");
+	tr_insert_new_(cuesheet, 0, 0, indx);
+	if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, indx)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	indx.offset = 20;
+	indx.number = 3;
+	printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on middle of non-empty array...");
+	tr_insert_new_(cuesheet, 0, 1, indx);
+	if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 1, indx)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	indx.offset = 30;
+	indx.number = 4;
+	printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on end of non-empty array...");
+	tr_insert_new_(cuesheet, 0, 3, indx);
+	if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 3, indx)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	indx.offset = 0;
+	indx.number = 0;
+	printf("testing FLAC__metadata_object_cuesheet_track_insert_blank_index() on end of non-empty array...");
+	tr_insert_new_(cuesheet, 0, 4, indx);
+	if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(block, 0, 4)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on end of array...");
+	tr_delete_(cuesheet, 0, 4);
+	if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 4)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on middle of array...");
+	tr_delete_(cuesheet, 0, 2);
+	if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on end of array...");
+	tr_delete_(cuesheet, 0, 2);
+	if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on beginning of array...");
+	tr_delete_(cuesheet, 0, 0);
+	if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 0)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(cuesheet);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	cuesheet = FLAC__metadata_object_clone(block);
+	if(0 == cuesheet) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on empty array...");
+	cs_insert_new_(&track, cuesheet, 0, 60, 7, "GBCDE1234567", false, false);
+	track_clone_(&track);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on beginning of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 0, 70, 8, "HBCDE1234567", false, false);
+	track_clone_(&track);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on middle of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 1, 80, 9, "IBCDE1234567", false, false);
+	track_clone_(&track);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, &track, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on end of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 3, 90, 10, "JBCDE1234567", false, false);
+	track_clone_(&track);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, &track, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array...");
+	cs_delete_(cuesheet, 2);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+	cs_delete_(cuesheet, 2);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array...");
+	cs_delete_(cuesheet, 0);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_set_track(own)...");
+	cs_set_new_(&track, cuesheet, 0, 100, 11, "KBCDE1234567", false, false);
+	track_clone_(&track);
+	FLAC__metadata_object_cuesheet_set_track(block, 0, &track, /*copy=*/false);
+	if(!mutils__compare_block(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_cuesheet_is_legal(block, /*check_cd_da_subset=*/true, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(cuesheet);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing PICTURE\n");
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	expected_length = (
+		FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+		FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN +
+		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
+	) / 8;
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	picture = FLAC__metadata_object_clone(block);
+	if(0 == picture) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	pi_set_mime_type(picture, "image/png\t");
+	printf("testing FLAC__metadata_object_picture_set_mime_type(copy)...");
+	if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png\t", /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	pi_set_mime_type(picture, "image/png");
+	printf("testing FLAC__metadata_object_picture_set_mime_type(copy)...");
+	if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png", /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned false, violation=\"%s\"\n", violation);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff");
+	printf("testing FLAC__metadata_object_picture_set_description(copy)...");
+	if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION\xff", /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION");
+	printf("testing FLAC__metadata_object_picture_set_description(copy)...");
+	if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION", /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned false, violation=\"%s\"\n", violation);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+
+	pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"));
+	printf("testing FLAC__metadata_object_picture_set_data(copy)...");
+	if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)"PNGDATA", strlen("PNGDATA"), /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	pi_set_mime_type(picture, "image/png\t");
+	printf("testing FLAC__metadata_object_picture_set_mime_type(own)...");
+	if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png\t"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	pi_set_mime_type(picture, "image/png");
+	printf("testing FLAC__metadata_object_picture_set_mime_type(own)...");
+	if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned false, violation=\"%s\"\n", violation);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff");
+	printf("testing FLAC__metadata_object_picture_set_description(own)...");
+	if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION\xff"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION");
+	printf("testing FLAC__metadata_object_picture_set_description(own)...");
+	if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned false, violation=\"%s\"\n", violation);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"));
+	printf("testing FLAC__metadata_object_picture_set_data(own)...");
+	if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)strdup("PNGDATA"), strlen("PNGDATA"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(picture);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	return true;
+}
diff --git a/src/test_libFLAC/test_libFLAC.vcproj b/src/test_libFLAC/test_libFLAC.vcproj
new file mode 100644
index 0000000..8689eeb
--- /dev/null
+++ b/src/test_libFLAC/test_libFLAC.vcproj
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="test_libFLAC"

+	ProjectGUID="{4cefbc8c-c215-11db-8314-0800200c9a66}"

+	RootNamespace="test_libFLAC"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\libFLAC\include;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;CPU_IS_LITTLE_ENDIAN=1"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\libFLAC\include;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;CPU_IS_LITTLE_ENDIAN=1"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\bitreader.h"

+				>

+			</File>

+			<File

+				RelativePath=".\bitwriter.h"

+				>

+			</File>

+			<File

+				RelativePath=".\crc.h"

+				>

+			</File>

+			<File

+				RelativePath=".\decoders.h"

+				>

+			</File>

+			<File

+				RelativePath=".\encoders.h"

+				>

+			</File>

+			<File

+				RelativePath=".\endswap.h"

+				>

+			</File>

+			<File

+				RelativePath=".\format.h"

+				>

+			</File>

+			<File

+				RelativePath=".\md5.h"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\bitreader.c"

+				>

+			</File>

+			<File

+				RelativePath=".\bitwriter.c"

+				>

+			</File>

+			<File

+				RelativePath=".\crc.c"

+				>

+			</File>

+			<File

+				RelativePath=".\decoders.c"

+				>

+			</File>

+			<File

+				RelativePath=".\encoders.c"

+				>

+			</File>

+			<File

+				RelativePath=".\endswap.c"

+				>

+			</File>

+			<File

+				RelativePath=".\format.c"

+				>

+			</File>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+			<File

+				RelativePath=".\md5.c"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata.c"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_manip.c"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_object.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/test_libFLAC/test_libFLAC.vcxproj b/src/test_libFLAC/test_libFLAC.vcxproj
new file mode 100644
index 0000000..062b2ae
--- /dev/null
+++ b/src/test_libFLAC/test_libFLAC.vcxproj
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc8c-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>test_libFLAC</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\libFLAC\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;CPU_IS_LITTLE_ENDIAN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\libFLAC\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;ENABLE_64_BIT_WORDS;CPU_IS_LITTLE_ENDIAN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\libFLAC\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;CPU_IS_LITTLE_ENDIAN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\libFLAC\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;ENABLE_64_BIT_WORDS;CPU_IS_LITTLE_ENDIAN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClInclude Include="bitreader.h" />

+    <ClInclude Include="bitwriter.h" />

+    <ClInclude Include="crc.h" />

+    <ClInclude Include="decoders.h" />

+    <ClInclude Include="encoders.h" />

+    <ClInclude Include="endswap.h" />

+    <ClInclude Include="format.h" />

+    <ClInclude Include="md5.h" />

+    <ClInclude Include="metadata.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="bitreader.c" />

+    <ClCompile Include="bitwriter.c" />

+    <ClCompile Include="crc.c" />

+    <ClCompile Include="decoders.c" />

+    <ClCompile Include="encoders.c" />

+    <ClCompile Include="endswap.c" />

+    <ClCompile Include="format.c" />

+    <ClCompile Include="main.c" />

+    <ClCompile Include="md5.c" />

+    <ClCompile Include="metadata.c" />

+    <ClCompile Include="metadata_manip.c" />

+    <ClCompile Include="metadata_object.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\share\grabbag\grabbag_static.vcxproj">

+      <Project>{4cefbc81-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\test_libs_common\test_libs_common_static.vcxproj">

+      <Project>{4cefbc8e-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_libFLAC/test_libFLAC.vcxproj.filters b/src/test_libFLAC/test_libFLAC.vcxproj.filters
new file mode 100644
index 0000000..862efb6
--- /dev/null
+++ b/src/test_libFLAC/test_libFLAC.vcxproj.filters
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="bitreader.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="bitwriter.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="crc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="decoders.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="encoders.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="endswap.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="format.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="md5.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="metadata.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="bitreader.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="bitwriter.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="crc.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="decoders.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="encoders.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="endswap.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="format.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="md5.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_manip.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_object.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_libs_common/CMakeLists.txt b/src/test_libs_common/CMakeLists.txt
new file mode 100644
index 0000000..8a0c871
--- /dev/null
+++ b/src/test_libs_common/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(test_libs_common STATIC
+    file_utils_flac.c
+    metadata_utils.c)
+target_link_libraries(test_libs_common PUBLIC FLAC)
diff --git a/src/test_libs_common/Makefile.am b/src/test_libs_common/Makefile.am
new file mode 100644
index 0000000..a72530e
--- /dev/null
+++ b/src/test_libs_common/Makefile.am
@@ -0,0 +1,33 @@
+#  test_libs_common - Common code to library unit tests
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libtest_libs_common.la
+
+libtest_libs_common_la_SOURCES = \
+	file_utils_flac.c \
+	metadata_utils.c
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	README \
+	test_libs_common_static.vcproj \
+	test_libs_common_static.vcxproj \
+	test_libs_common_static.vcxproj.filters
diff --git a/src/test_libs_common/Makefile.lite b/src/test_libs_common/Makefile.lite
new file mode 100644
index 0000000..13f1051
--- /dev/null
+++ b/src/test_libs_common/Makefile.lite
@@ -0,0 +1,42 @@
+#  test_libs_common - Common code to library unit tests
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+LIB_NAME = libtest_libs_common
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lFLAC $(OGG_LIBS) -lm
+endif
+
+INCLUDES = -I$(topdir)/include
+
+SRCS_C = \
+	file_utils_flac.c \
+	metadata_utils.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_libs_common/README b/src/test_libs_common/README
new file mode 100644
index 0000000..6a704c2
--- /dev/null
+++ b/src/test_libs_common/README
@@ -0,0 +1,2 @@
+This directory contains a convenience library of routines that are
+common to the library unit testers.
diff --git a/src/test_libs_common/file_utils_flac.c b/src/test_libs_common/file_utils_flac.c
new file mode 100644
index 0000000..28ab08d
--- /dev/null
+++ b/src/test_libs_common/file_utils_flac.c
@@ -0,0 +1,155 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/stream_encoder.h"
+#include "test_libs_common/file_utils_flac.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h> /* for stat() */
+#include "share/compat.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+const long file_utils__ogg_serial_number = 12345;
+
+#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
+
+typedef struct {
+	FILE *file;
+} encoder_client_struct;
+
+static FLAC__StreamEncoderWriteStatus encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data)
+{
+	encoder_client_struct *ecd = (encoder_client_struct*)client_data;
+
+	(void)encoder, (void)samples, (void)current_frame;
+
+	if(local__fwrite(buffer, 1, bytes, ecd->file) != bytes)
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+	else
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static void encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	(void)encoder, (void)metadata, (void)client_data;
+}
+
+FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, FLAC__off_t *output_filesize, uint32_t length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, uint32_t num_metadata)
+{
+	FLAC__int32 samples[1024];
+	FLAC__StreamEncoder *encoder;
+	FLAC__StreamEncoderInitStatus init_status;
+	encoder_client_struct encoder_client_data;
+	uint32_t i, n;
+
+	FLAC__ASSERT(0 != output_filename);
+	FLAC__ASSERT(0 != streaminfo);
+	FLAC__ASSERT(streaminfo->type == FLAC__METADATA_TYPE_STREAMINFO);
+	FLAC__ASSERT((streaminfo->is_last && num_metadata == 0) || (!streaminfo->is_last && num_metadata > 0));
+
+	if(0 == (encoder_client_data.file = flac_fopen(output_filename, "wb")))
+		return false;
+
+	encoder = FLAC__stream_encoder_new();
+	if(0 == encoder) {
+		fclose(encoder_client_data.file);
+		return false;
+	}
+
+	FLAC__stream_encoder_set_ogg_serial_number(encoder, file_utils__ogg_serial_number);
+	FLAC__stream_encoder_set_verify(encoder, true);
+	FLAC__stream_encoder_set_streamable_subset(encoder, true);
+	FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false);
+	FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false);
+	FLAC__stream_encoder_set_channels(encoder, streaminfo->data.stream_info.channels);
+	FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo->data.stream_info.bits_per_sample);
+	FLAC__stream_encoder_set_sample_rate(encoder, streaminfo->data.stream_info.sample_rate);
+	FLAC__stream_encoder_set_blocksize(encoder, streaminfo->data.stream_info.min_blocksize);
+	FLAC__stream_encoder_set_max_lpc_order(encoder, 0);
+	FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0);
+	FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false);
+	FLAC__stream_encoder_set_do_escape_coding(encoder, false);
+	FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false);
+	FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0);
+	FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0);
+	FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0);
+	FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo->data.stream_info.total_samples);
+	FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata);
+
+	if(is_ogg)
+		init_status = FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data);
+	else
+		init_status = FLAC__stream_encoder_init_stream(encoder, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data);
+
+	if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+		fclose(encoder_client_data.file);
+		return false;
+	}
+
+	/* init the dummy sample buffer */
+	for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+		samples[i] = i & 7;
+
+	while(length > 0) {
+		n = min(length, sizeof(samples) / sizeof(FLAC__int32));
+
+		if(!FLAC__stream_encoder_process_interleaved(encoder, samples, n)) {
+			fclose(encoder_client_data.file);
+			return false;
+		}
+
+		length -= n;
+	}
+
+	(void)FLAC__stream_encoder_finish(encoder);
+
+	fclose(encoder_client_data.file);
+
+	FLAC__stream_encoder_delete(encoder);
+
+	if(0 != output_filesize) {
+		struct flac_stat_s filestats;
+
+		if(flac_stat(output_filename, &filestats) != 0)
+			return false;
+		else
+			*output_filesize = filestats.st_size;
+	}
+
+	return true;
+}
diff --git a/src/test_libs_common/metadata_utils.c b/src/test_libs_common/metadata_utils.c
new file mode 100644
index 0000000..a3f4499
--- /dev/null
+++ b/src/test_libs_common/metadata_utils.c
@@ -0,0 +1,635 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * These are not tests, just utility functions used by the metadata tests
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "test_libs_common/metadata_utils.h"
+#include "share/compat.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+
+FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy)
+{
+	if(blockcopy->min_blocksize != block->min_blocksize) {
+		printf("FAILED, min_blocksize mismatch, expected %u, got %u\n", block->min_blocksize, blockcopy->min_blocksize);
+		return false;
+	}
+	if(blockcopy->max_blocksize != block->max_blocksize) {
+		printf("FAILED, max_blocksize mismatch, expected %u, got %u\n", block->max_blocksize, blockcopy->max_blocksize);
+		return false;
+	}
+	if(blockcopy->min_framesize != block->min_framesize) {
+		printf("FAILED, min_framesize mismatch, expected %u, got %u\n", block->min_framesize, blockcopy->min_framesize);
+		return false;
+	}
+	if(blockcopy->max_framesize != block->max_framesize) {
+		printf("FAILED, max_framesize mismatch, expected %u, got %u\n", block->max_framesize, blockcopy->max_framesize);
+		return false;
+	}
+	if(blockcopy->sample_rate != block->sample_rate) {
+		printf("FAILED, sample_rate mismatch, expected %u, got %u\n", block->sample_rate, blockcopy->sample_rate);
+		return false;
+	}
+	if(blockcopy->channels != block->channels) {
+		printf("FAILED, channels mismatch, expected %u, got %u\n", block->channels, blockcopy->channels);
+		return false;
+	}
+	if(blockcopy->bits_per_sample != block->bits_per_sample) {
+		printf("FAILED, bits_per_sample mismatch, expected %u, got %u\n", block->bits_per_sample, blockcopy->bits_per_sample);
+		return false;
+	}
+	if(blockcopy->total_samples != block->total_samples) {
+		printf("FAILED, total_samples mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", block->total_samples, blockcopy->total_samples);
+		return false;
+	}
+	if(0 != memcmp(blockcopy->md5sum, block->md5sum, sizeof(block->md5sum))) {
+		printf("FAILED, md5sum mismatch, expected %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X, got %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
+			(uint32_t)block->md5sum[0],
+			(uint32_t)block->md5sum[1],
+			(uint32_t)block->md5sum[2],
+			(uint32_t)block->md5sum[3],
+			(uint32_t)block->md5sum[4],
+			(uint32_t)block->md5sum[5],
+			(uint32_t)block->md5sum[6],
+			(uint32_t)block->md5sum[7],
+			(uint32_t)block->md5sum[8],
+			(uint32_t)block->md5sum[9],
+			(uint32_t)block->md5sum[10],
+			(uint32_t)block->md5sum[11],
+			(uint32_t)block->md5sum[12],
+			(uint32_t)block->md5sum[13],
+			(uint32_t)block->md5sum[14],
+			(uint32_t)block->md5sum[15],
+			(uint32_t)blockcopy->md5sum[0],
+			(uint32_t)blockcopy->md5sum[1],
+			(uint32_t)blockcopy->md5sum[2],
+			(uint32_t)blockcopy->md5sum[3],
+			(uint32_t)blockcopy->md5sum[4],
+			(uint32_t)blockcopy->md5sum[5],
+			(uint32_t)blockcopy->md5sum[6],
+			(uint32_t)blockcopy->md5sum[7],
+			(uint32_t)blockcopy->md5sum[8],
+			(uint32_t)blockcopy->md5sum[9],
+			(uint32_t)blockcopy->md5sum[10],
+			(uint32_t)blockcopy->md5sum[11],
+			(uint32_t)blockcopy->md5sum[12],
+			(uint32_t)blockcopy->md5sum[13],
+			(uint32_t)blockcopy->md5sum[14],
+			(uint32_t)blockcopy->md5sum[15]
+		);
+		return false;
+	}
+	return true;
+}
+
+FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, uint32_t block_length)
+{
+	/* we don't compare the padding guts */
+	(void)block, (void)blockcopy, (void)block_length;
+	return true;
+}
+
+FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, uint32_t block_length)
+{
+	if(block_length < sizeof(block->id)) {
+		printf("FAILED, bad block length = %u\n", block_length);
+		return false;
+	}
+	if(0 != memcmp(blockcopy->id, block->id, sizeof(block->id))) {
+		printf("FAILED, id mismatch, expected %02X%02X%02X%02X, got %02X%02X%02X%02X\n",
+			(uint32_t)block->id[0],
+			(uint32_t)block->id[1],
+			(uint32_t)block->id[2],
+			(uint32_t)block->id[3],
+			(uint32_t)blockcopy->id[0],
+			(uint32_t)blockcopy->id[1],
+			(uint32_t)blockcopy->id[2],
+			(uint32_t)blockcopy->id[3]
+		);
+		return false;
+	}
+	if(0 == block->data || 0 == blockcopy->data) {
+		if(block->data != blockcopy->data) {
+			printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy");
+			return false;
+		}
+		else if(block_length - sizeof(block->id) > 0) {
+			printf("FAILED, data pointer is null but block length is not 0\n");
+			return false;
+		}
+	}
+	else {
+		if(block_length - sizeof(block->id) == 0) {
+			printf("FAILED, data pointer is not null but block length is 0\n");
+			return false;
+		}
+		else if(0 != memcmp(blockcopy->data, block->data, block_length - sizeof(block->id))) {
+			printf("FAILED, data mismatch\n");
+			return false;
+		}
+	}
+	return true;
+}
+
+FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy)
+{
+	uint32_t i;
+	if(blockcopy->num_points != block->num_points) {
+		printf("FAILED, num_points mismatch, expected %u, got %u\n", block->num_points, blockcopy->num_points);
+		return false;
+	}
+	for(i = 0; i < block->num_points; i++) {
+		if(blockcopy->points[i].sample_number != block->points[i].sample_number) {
+			printf("FAILED, points[%u].sample_number mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->points[i].sample_number, blockcopy->points[i].sample_number);
+			return false;
+		}
+		if(blockcopy->points[i].stream_offset != block->points[i].stream_offset) {
+			printf("FAILED, points[%u].stream_offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->points[i].stream_offset, blockcopy->points[i].stream_offset);
+			return false;
+		}
+		if(blockcopy->points[i].frame_samples != block->points[i].frame_samples) {
+			printf("FAILED, points[%u].frame_samples mismatch, expected %u, got %u\n", i, block->points[i].frame_samples, blockcopy->points[i].frame_samples);
+			return false;
+		}
+	}
+	return true;
+}
+
+FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy)
+{
+	uint32_t i;
+	if(blockcopy->vendor_string.length != block->vendor_string.length) {
+		printf("FAILED, vendor_string.length mismatch, expected %u, got %u\n", block->vendor_string.length, blockcopy->vendor_string.length);
+		return false;
+	}
+	if(0 == block->vendor_string.entry || 0 == blockcopy->vendor_string.entry) {
+		if(block->vendor_string.entry != blockcopy->vendor_string.entry) {
+			printf("FAILED, vendor_string.entry mismatch\n");
+			return false;
+		}
+	}
+	else if(0 != memcmp(blockcopy->vendor_string.entry, block->vendor_string.entry, block->vendor_string.length)) {
+		printf("FAILED, vendor_string.entry mismatch\n");
+		return false;
+	}
+	if(blockcopy->num_comments != block->num_comments) {
+		printf("FAILED, num_comments mismatch, expected %u, got %u\n", block->num_comments, blockcopy->num_comments);
+		return false;
+	}
+	for(i = 0; i < block->num_comments; i++) {
+		if(blockcopy->comments[i].length != block->comments[i].length) {
+			printf("FAILED, comments[%u].length mismatch, expected %u, got %u\n", i, block->comments[i].length, blockcopy->comments[i].length);
+			return false;
+		}
+		if(0 == block->comments[i].entry || 0 == blockcopy->comments[i].entry) {
+			if(block->comments[i].entry != blockcopy->comments[i].entry) {
+				printf("FAILED, comments[%u].entry mismatch\n", i);
+				return false;
+			}
+		}
+		else {
+			if(0 != memcmp(blockcopy->comments[i].entry, block->comments[i].entry, block->comments[i].length)) {
+				printf("FAILED, comments[%u].entry mismatch\n", i);
+				return false;
+			}
+		}
+	}
+	return true;
+}
+
+FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy)
+{
+	uint32_t i, j;
+
+	if(0 != strcmp(blockcopy->media_catalog_number, block->media_catalog_number)) {
+		printf("FAILED, media_catalog_number mismatch, expected %s, got %s\n", block->media_catalog_number, blockcopy->media_catalog_number);
+		return false;
+	}
+	if(blockcopy->lead_in != block->lead_in) {
+		printf("FAILED, lead_in mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", block->lead_in, blockcopy->lead_in);
+		return false;
+	}
+	if(blockcopy->is_cd != block->is_cd) {
+		printf("FAILED, is_cd mismatch, expected %u, got %u\n", (uint32_t)block->is_cd, (uint32_t)blockcopy->is_cd);
+		return false;
+	}
+	if(blockcopy->num_tracks != block->num_tracks) {
+		printf("FAILED, num_tracks mismatch, expected %u, got %u\n", block->num_tracks, blockcopy->num_tracks);
+		return false;
+	}
+	for(i = 0; i < block->num_tracks; i++) {
+		if(blockcopy->tracks[i].offset != block->tracks[i].offset) {
+			printf("FAILED, tracks[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->tracks[i].offset, blockcopy->tracks[i].offset);
+			return false;
+		}
+		if(blockcopy->tracks[i].number != block->tracks[i].number) {
+			printf("FAILED, tracks[%u].number mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].number, (uint32_t)blockcopy->tracks[i].number);
+			return false;
+		}
+		if(blockcopy->tracks[i].num_indices != block->tracks[i].num_indices) {
+			printf("FAILED, tracks[%u].num_indices mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].num_indices, (uint32_t)blockcopy->tracks[i].num_indices);
+			return false;
+		}
+		/* num_indices == 0 means lead-out track so only the track offset and number are valid */
+		if(block->tracks[i].num_indices > 0) {
+			if(0 != strcmp(blockcopy->tracks[i].isrc, block->tracks[i].isrc)) {
+				printf("FAILED, tracks[%u].isrc mismatch, expected %s, got %s\n", i, block->tracks[i].isrc, blockcopy->tracks[i].isrc);
+				return false;
+			}
+			if(blockcopy->tracks[i].type != block->tracks[i].type) {
+				printf("FAILED, tracks[%u].type mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].type, (uint32_t)blockcopy->tracks[i].type);
+				return false;
+			}
+			if(blockcopy->tracks[i].pre_emphasis != block->tracks[i].pre_emphasis) {
+				printf("FAILED, tracks[%u].pre_emphasis mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].pre_emphasis, (uint32_t)blockcopy->tracks[i].pre_emphasis);
+				return false;
+			}
+			if(0 == block->tracks[i].indices || 0 == blockcopy->tracks[i].indices) {
+				if(block->tracks[i].indices != blockcopy->tracks[i].indices) {
+					printf("FAILED, tracks[%u].indices mismatch\n", i);
+					return false;
+				}
+			}
+			else {
+				for(j = 0; j < block->tracks[i].num_indices; j++) {
+					if(blockcopy->tracks[i].indices[j].offset != block->tracks[i].indices[j].offset) {
+						printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, j, block->tracks[i].indices[j].offset, blockcopy->tracks[i].indices[j].offset);
+						return false;
+					}
+					if(blockcopy->tracks[i].indices[j].number != block->tracks[i].indices[j].number) {
+						printf("FAILED, tracks[%u].indices[%u].number mismatch, expected %u, got %u\n", i, j, (uint32_t)block->tracks[i].indices[j].number, (uint32_t)blockcopy->tracks[i].indices[j].number);
+						return false;
+					}
+				}
+			}
+		}
+	}
+	return true;
+}
+
+FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy)
+{
+	size_t len, lencopy;
+	if(blockcopy->type != block->type) {
+		printf("FAILED, type mismatch, expected %u, got %u\n", (uint32_t)block->type, (uint32_t)blockcopy->type);
+		return false;
+	}
+	len = strlen(block->mime_type);
+	lencopy = strlen(blockcopy->mime_type);
+	if(lencopy != len) {
+		printf("FAILED, mime_type length mismatch, expected %u, got %u\n", (uint32_t)len, (uint32_t)lencopy);
+		return false;
+	}
+	if(strcmp(blockcopy->mime_type, block->mime_type)) {
+		printf("FAILED, mime_type mismatch, expected %s, got %s\n", block->mime_type, blockcopy->mime_type);
+		return false;
+	}
+	len = strlen((const char *)block->description);
+	lencopy = strlen((const char *)blockcopy->description);
+	if(lencopy != len) {
+		printf("FAILED, description length mismatch, expected %u, got %u\n", (uint32_t)len, (uint32_t)lencopy);
+		return false;
+	}
+	if(strcmp((const char *)blockcopy->description, (const char *)block->description)) {
+		printf("FAILED, description mismatch, expected %s, got %s\n", block->description, blockcopy->description);
+		return false;
+	}
+	if(blockcopy->width != block->width) {
+		printf("FAILED, width mismatch, expected %u, got %u\n", block->width, blockcopy->width);
+		return false;
+	}
+	if(blockcopy->height != block->height) {
+		printf("FAILED, height mismatch, expected %u, got %u\n", block->height, blockcopy->height);
+		return false;
+	}
+	if(blockcopy->depth != block->depth) {
+		printf("FAILED, depth mismatch, expected %u, got %u\n", block->depth, blockcopy->depth);
+		return false;
+	}
+	if(blockcopy->colors != block->colors) {
+		printf("FAILED, colors mismatch, expected %u, got %u\n", block->colors, blockcopy->colors);
+		return false;
+	}
+	if(blockcopy->data_length != block->data_length) {
+		printf("FAILED, data_length mismatch, expected %u, got %u\n", block->data_length, blockcopy->data_length);
+		return false;
+	}
+	if(block->data_length > 0 && memcmp(blockcopy->data, block->data, block->data_length)) {
+		printf("FAILED, data mismatch\n");
+		return false;
+	}
+	return true;
+}
+
+FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, uint32_t block_length)
+{
+	if(0 == block->data || 0 == blockcopy->data) {
+		if(block->data != blockcopy->data) {
+			printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy");
+			return false;
+		}
+		else if(block_length > 0) {
+			printf("FAILED, data pointer is null but block length is not 0\n");
+			return false;
+		}
+	}
+	else {
+		if(block_length == 0) {
+			printf("FAILED, data pointer is not null but block length is 0\n");
+			return false;
+		}
+		else if(0 != memcmp(blockcopy->data, block->data, block_length)) {
+			printf("FAILED, data mismatch\n");
+			return false;
+		}
+	}
+	return true;
+}
+
+FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy)
+{
+	if(blockcopy->type != block->type) {
+		printf("FAILED, type mismatch, expected %s, got %s\n", FLAC__MetadataTypeString[block->type], FLAC__MetadataTypeString[blockcopy->type]);
+		return false;
+	}
+	if(blockcopy->is_last != block->is_last) {
+		printf("FAILED, is_last mismatch, expected %u, got %u\n", (uint32_t)block->is_last, (uint32_t)blockcopy->is_last);
+		return false;
+	}
+	if(blockcopy->length != block->length) {
+		printf("FAILED, length mismatch, expected %u, got %u\n", block->length, blockcopy->length);
+		return false;
+	}
+	switch(block->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return mutils__compare_block_data_streaminfo(&block->data.stream_info, &blockcopy->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return mutils__compare_block_data_padding(&block->data.padding, &blockcopy->data.padding, block->length);
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return mutils__compare_block_data_application(&block->data.application, &blockcopy->data.application, block->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return mutils__compare_block_data_seektable(&block->data.seek_table, &blockcopy->data.seek_table);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return mutils__compare_block_data_vorbiscomment(&block->data.vorbis_comment, &blockcopy->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return mutils__compare_block_data_cuesheet(&block->data.cue_sheet, &blockcopy->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return mutils__compare_block_data_picture(&block->data.picture, &blockcopy->data.picture);
+		default:
+			return mutils__compare_block_data_unknown(&block->data.unknown, &blockcopy->data.unknown, block->length);
+	}
+}
+
+static void *malloc_or_die_(size_t size)
+{
+	void *x = malloc(size);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size);
+		exit(1);
+	}
+	return x;
+}
+
+static void *calloc_or_die_(size_t n, size_t size)
+{
+	void *x = calloc(n, size);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)n * (uint32_t)size);
+		exit(1);
+	}
+	return x;
+}
+
+static char *strdup_or_die_(const char *s)
+{
+	char *x = strdup(s);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+		exit(1);
+	}
+	return x;
+}
+
+void mutils__init_metadata_blocks(
+	FLAC__StreamMetadata *streaminfo,
+	FLAC__StreamMetadata *padding,
+	FLAC__StreamMetadata *seektable,
+	FLAC__StreamMetadata *application1,
+	FLAC__StreamMetadata *application2,
+	FLAC__StreamMetadata *vorbiscomment,
+	FLAC__StreamMetadata *cuesheet,
+	FLAC__StreamMetadata *picture,
+	FLAC__StreamMetadata *unknown
+)
+{
+	/*
+		most of the actual numbers and data in the blocks don't matter,
+		we just want to make sure the decoder parses them correctly
+
+		remember, the metadata interface gets tested after the decoders,
+		so we do all the metadata manipulation here without it.
+	*/
+
+	/* min/max_framesize and md5sum don't get written at first, so we have to leave them 0 */
+	streaminfo->is_last = false;
+	streaminfo->type = FLAC__METADATA_TYPE_STREAMINFO;
+	streaminfo->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+	streaminfo->data.stream_info.min_blocksize = 576;
+	streaminfo->data.stream_info.max_blocksize = 576;
+	streaminfo->data.stream_info.min_framesize = 0;
+	streaminfo->data.stream_info.max_framesize = 0;
+	streaminfo->data.stream_info.sample_rate = 44100;
+	streaminfo->data.stream_info.channels = 1;
+	streaminfo->data.stream_info.bits_per_sample = 8;
+	streaminfo->data.stream_info.total_samples = 0;
+	memset(streaminfo->data.stream_info.md5sum, 0, 16);
+
+	padding->is_last = false;
+	padding->type = FLAC__METADATA_TYPE_PADDING;
+	padding->length = 1234;
+
+	seektable->is_last = false;
+	seektable->type = FLAC__METADATA_TYPE_SEEKTABLE;
+	seektable->data.seek_table.num_points = 2;
+	seektable->length = seektable->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+	seektable->data.seek_table.points = malloc_or_die_(seektable->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint));
+	seektable->data.seek_table.points[0].sample_number = 0;
+	seektable->data.seek_table.points[0].stream_offset = 0;
+	seektable->data.seek_table.points[0].frame_samples = streaminfo->data.stream_info.min_blocksize;
+	seektable->data.seek_table.points[1].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+	seektable->data.seek_table.points[1].stream_offset = 1000;
+	seektable->data.seek_table.points[1].frame_samples = streaminfo->data.stream_info.min_blocksize;
+
+	application1->is_last = false;
+	application1->type = FLAC__METADATA_TYPE_APPLICATION;
+	application1->length = 8;
+	memcpy(application1->data.application.id, "This", 4);
+	application1->data.application.data = malloc_or_die_(4);
+	memcpy(application1->data.application.data, "\xf0\xe1\xd2\xc3", 4);
+
+	application2->is_last = false;
+	application2->type = FLAC__METADATA_TYPE_APPLICATION;
+	application2->length = 4;
+	memcpy(application2->data.application.id, "Here", 4);
+	application2->data.application.data = 0;
+
+	{
+		const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING);
+		vorbiscomment->is_last = false;
+		vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+		vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0);
+		vorbiscomment->data.vorbis_comment.vendor_string.length = vendor_string_length;
+		vorbiscomment->data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1);
+		memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
+		vorbiscomment->data.vorbis_comment.num_comments = 2;
+		vorbiscomment->data.vorbis_comment.comments = malloc_or_die_(vorbiscomment->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+		vorbiscomment->data.vorbis_comment.comments[0].length = 5;
+		vorbiscomment->data.vorbis_comment.comments[0].entry = malloc_or_die_(5+1);
+		memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1);
+		vorbiscomment->data.vorbis_comment.comments[1].length = 0;
+		vorbiscomment->data.vorbis_comment.comments[1].entry = 0;
+	}
+
+	cuesheet->is_last = false;
+	cuesheet->type = FLAC__METADATA_TYPE_CUESHEET;
+	cuesheet->length =
+		/* cuesheet guts */
+		(
+			FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+		) / 8 +
+		/* 2 tracks */
+		3 * (
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+		) / 8 +
+		/* 3 index points */
+		3 * (
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+		) / 8
+	;
+	memset(cuesheet->data.cue_sheet.media_catalog_number, 0, sizeof(cuesheet->data.cue_sheet.media_catalog_number));
+	cuesheet->data.cue_sheet.media_catalog_number[0] = 'j';
+	cuesheet->data.cue_sheet.media_catalog_number[1] = 'C';
+	cuesheet->data.cue_sheet.lead_in = 2 * 44100;
+	cuesheet->data.cue_sheet.is_cd = true;
+	cuesheet->data.cue_sheet.num_tracks = 3;
+	cuesheet->data.cue_sheet.tracks = calloc_or_die_(cuesheet->data.cue_sheet.num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+	cuesheet->data.cue_sheet.tracks[0].offset = 0;
+	cuesheet->data.cue_sheet.tracks[0].number = 1;
+	memcpy(cuesheet->data.cue_sheet.tracks[0].isrc, "ACBDE1234567", sizeof(cuesheet->data.cue_sheet.tracks[0].isrc));
+	cuesheet->data.cue_sheet.tracks[0].type = 0;
+	cuesheet->data.cue_sheet.tracks[0].pre_emphasis = 1;
+	cuesheet->data.cue_sheet.tracks[0].num_indices = 2;
+	cuesheet->data.cue_sheet.tracks[0].indices = malloc_or_die_(cuesheet->data.cue_sheet.tracks[0].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+	cuesheet->data.cue_sheet.tracks[0].indices[0].offset = 0;
+	cuesheet->data.cue_sheet.tracks[0].indices[0].number = 0;
+	cuesheet->data.cue_sheet.tracks[0].indices[1].offset = 123 * 588;
+	cuesheet->data.cue_sheet.tracks[0].indices[1].number = 1;
+	cuesheet->data.cue_sheet.tracks[1].offset = 1234 * 588;
+	cuesheet->data.cue_sheet.tracks[1].number = 2;
+	memcpy(cuesheet->data.cue_sheet.tracks[1].isrc, "ACBDE7654321", sizeof(cuesheet->data.cue_sheet.tracks[1].isrc));
+	cuesheet->data.cue_sheet.tracks[1].type = 1;
+	cuesheet->data.cue_sheet.tracks[1].pre_emphasis = 0;
+	cuesheet->data.cue_sheet.tracks[1].num_indices = 1;
+	cuesheet->data.cue_sheet.tracks[1].indices = malloc_or_die_(cuesheet->data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+	cuesheet->data.cue_sheet.tracks[1].indices[0].offset = 0;
+	cuesheet->data.cue_sheet.tracks[1].indices[0].number = 1;
+	cuesheet->data.cue_sheet.tracks[2].offset = 12345 * 588;
+	cuesheet->data.cue_sheet.tracks[2].number = 170;
+	cuesheet->data.cue_sheet.tracks[2].num_indices = 0;
+
+	picture->is_last = false;
+	picture->type = FLAC__METADATA_TYPE_PICTURE;
+	picture->length =
+		(
+			FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+			FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+			FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+			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 /* will add the length for the data later */
+		) / 8
+	;
+	picture->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+	picture->data.picture.mime_type = strdup_or_die_("image/jpeg");
+	picture->length += strlen(picture->data.picture.mime_type);
+	picture->data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+	picture->length += strlen((const char *)picture->data.picture.description);
+	picture->data.picture.width = 300;
+	picture->data.picture.height = 300;
+	picture->data.picture.depth = 24;
+	picture->data.picture.colors = 0;
+	picture->data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+	picture->data.picture.data_length = strlen((const char *)picture->data.picture.data);
+	picture->length += picture->data.picture.data_length;
+
+	unknown->is_last = true;
+	unknown->type = 126;
+	unknown->length = 8;
+	unknown->data.unknown.data = malloc_or_die_(unknown->length);
+	memcpy(unknown->data.unknown.data, "\xfe\xdc\xba\x98\xf0\xe1\xd2\xc3", unknown->length);
+}
+
+void mutils__free_metadata_blocks(
+	FLAC__StreamMetadata *streaminfo,
+	FLAC__StreamMetadata *padding,
+	FLAC__StreamMetadata *seektable,
+	FLAC__StreamMetadata *application1,
+	FLAC__StreamMetadata *application2,
+	FLAC__StreamMetadata *vorbiscomment,
+	FLAC__StreamMetadata *cuesheet,
+	FLAC__StreamMetadata *picture,
+	FLAC__StreamMetadata *unknown
+)
+{
+	(void)streaminfo, (void)padding, (void)application2;
+	free(seektable->data.seek_table.points);
+	free(application1->data.application.data);
+	free(vorbiscomment->data.vorbis_comment.vendor_string.entry);
+	free(vorbiscomment->data.vorbis_comment.comments[0].entry);
+	free(vorbiscomment->data.vorbis_comment.comments);
+	free(cuesheet->data.cue_sheet.tracks[0].indices);
+	free(cuesheet->data.cue_sheet.tracks[1].indices);
+	free(cuesheet->data.cue_sheet.tracks);
+	free(picture->data.picture.mime_type);
+	free(picture->data.picture.description);
+	free(picture->data.picture.data);
+	free(unknown->data.unknown.data);
+}
diff --git a/src/test_libs_common/test_libs_common_static.vcproj b/src/test_libs_common/test_libs_common_static.vcproj
new file mode 100644
index 0000000..763d3e7
--- /dev/null
+++ b/src/test_libs_common/test_libs_common_static.vcproj
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="test_libs_common_static"

+	ProjectGUID="{4cefbc8e-c215-11db-8314-0800200c9a66}"

+	RootNamespace="test_libs_common_static"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\lib"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".\include;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\file_utils_flac.c"

+				>

+			</File>

+			<File

+				RelativePath=".\metadata_utils.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/test_libs_common/test_libs_common_static.vcxproj b/src/test_libs_common/test_libs_common_static.vcxproj
new file mode 100644
index 0000000..812c8c3
--- /dev/null
+++ b/src/test_libs_common/test_libs_common_static.vcxproj
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc8e-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>test_libs_common_static</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.\include;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="file_utils_flac.c" />

+    <ClCompile Include="metadata_utils.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_libs_common/test_libs_common_static.vcxproj.filters b/src/test_libs_common/test_libs_common_static.vcxproj.filters
new file mode 100644
index 0000000..2d941fb
--- /dev/null
+++ b/src/test_libs_common/test_libs_common_static.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="file_utils_flac.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="metadata_utils.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_seeking/CMakeLists.txt b/src/test_seeking/CMakeLists.txt
new file mode 100644
index 0000000..5144291
--- /dev/null
+++ b/src/test_seeking/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(test_seeking
+    main.c
+    $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+    $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(test_seeking FLAC)
diff --git a/src/test_seeking/Makefile.am b/src/test_seeking/Makefile.am
new file mode 100644
index 0000000..a42d78d
--- /dev/null
+++ b/src/test_seeking/Makefile.am
@@ -0,0 +1,37 @@
+#  test_seeking - Seeking tester for libFLAC
+#  Copyright (C) 2004-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	test_seeking.vcproj \
+	test_seeking.vcxproj \
+	test_seeking.vcxproj.filters
+
+AM_CFLAGS = @OGG_CFLAGS@
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+
+check_PROGRAMS = test_seeking
+test_seeking_LDADD = \
+	$(top_builddir)/src/libFLAC/libFLAC.la
+
+test_seeking_SOURCES = \
+	main.c
+
+CLEANFILES = test_seeking.exe
diff --git a/src/test_seeking/Makefile.lite b/src/test_seeking/Makefile.lite
new file mode 100644
index 0000000..4c64540
--- /dev/null
+++ b/src/test_seeking/Makefile.lite
@@ -0,0 +1,43 @@
+#  test_seeking - Seeking tester for libFLAC
+#  Copyright (C) 2004-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = test_seeking
+
+INCLUDES = -I../libFLAC/include -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+    LIBS = -lFLAC $(OGG_LIBS) -lm
+endif
+
+SRCS_C = \
+	main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_seeking/main.c b/src/test_seeking/main.c
new file mode 100644
index 0000000..5a7e399
--- /dev/null
+++ b/src/test_seeking/main.c
@@ -0,0 +1,473 @@
+/* test_seeking - Seeking tester for libFLAC
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#include <sys/stat.h> /* for stat() */
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "FLAC/stream_decoder.h"
+#include "share/compat.h"
+
+typedef struct {
+	FLAC__int32 **pcm;
+	FLAC__bool got_data;
+	FLAC__uint64 total_samples;
+	uint32_t channels;
+	uint32_t bits_per_sample;
+	FLAC__bool quiet;
+	FLAC__bool ignore_errors;
+	FLAC__bool error_occurred;
+} DecoderClientData;
+
+static FLAC__bool stop_signal_ = false;
+
+static void our_sigint_handler_(int signum)
+{
+	(void)signum;
+	printf("(caught SIGINT) ");
+	fflush(stdout);
+	stop_signal_ = true;
+}
+
+static FLAC__bool die_(const char *msg)
+{
+	printf("ERROR: %s\n", msg);
+	return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
+{
+	FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder);
+
+	if(msg)
+		printf("FAILED, %s", msg);
+	else
+		printf("FAILED");
+
+	printf(", state = %u (%s)\n", (uint32_t)state, FLAC__StreamDecoderStateString[state]);
+
+	return false;
+}
+
+static uint32_t local_rand_(void)
+{
+#if !defined _MSC_VER && !defined __MINGW32__
+#define RNDFUNC random
+#else
+#define RNDFUNC rand
+#endif
+	/* every RAND_MAX I've ever seen is 2^15-1 or 2^31-1, so a little hackery here: */
+	if (RAND_MAX > 32767)
+		return RNDFUNC();
+	else /* usually MSVC, some solaris */
+		return (RNDFUNC()<<15) | RNDFUNC();
+#undef RNDFUNC
+}
+
+static FLAC__off_t get_filesize_(const char *srcpath)
+{
+	struct flac_stat_s srcstat;
+
+	if(0 == flac_stat(srcpath, &srcstat))
+		return srcstat.st_size;
+	else
+		return -1;
+}
+
+static FLAC__bool read_pcm_(FLAC__int32 *pcm[], const char *rawfilename, const char *flacfilename)
+{
+	FILE *f;
+	uint32_t channels = 0, bps = 0, samples, i, j;
+
+	FLAC__off_t rawfilesize = get_filesize_(rawfilename);
+	if (rawfilesize < 0) {
+		fprintf(stderr, "ERROR: can't determine filesize for %s\n", rawfilename);
+		return false;
+	}
+	/* get sample format from flac file; would just use FLAC__metadata_get_streaminfo() except it doesn't work for Ogg FLAC yet */
+	{
+#if 0
+		FLAC__StreamMetadata streaminfo;
+		if(!FLAC__metadata_get_streaminfo(flacfilename, &streaminfo)) {
+			printf("ERROR: getting STREAMINFO from %s\n", flacfilename);
+			return false;
+		}
+		channels = streaminfo.data.stream_info.channels;
+		bps = streaminfo.data.stream_info.bits_per_sample;
+#else
+		FLAC__bool ok = true;
+		FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
+		FLAC__Metadata_Iterator *it = 0;
+		ok = ok && chain && (FLAC__metadata_chain_read(chain, flacfilename) || FLAC__metadata_chain_read_ogg(chain, flacfilename));
+		ok = ok && (it = FLAC__metadata_iterator_new());
+		if(ok) FLAC__metadata_iterator_init(it, chain);
+		ok = ok && (FLAC__metadata_iterator_get_block(it)->type == FLAC__METADATA_TYPE_STREAMINFO);
+		ok = ok && (channels = FLAC__metadata_iterator_get_block(it)->data.stream_info.channels);
+		ok = ok && (bps = FLAC__metadata_iterator_get_block(it)->data.stream_info.bits_per_sample);
+		if(it) FLAC__metadata_iterator_delete(it);
+		if(chain) FLAC__metadata_chain_delete(chain);
+		if(!ok) {
+			printf("ERROR: getting STREAMINFO from %s\n", flacfilename);
+			return false;
+		}
+#endif
+	}
+	if(channels > 2) {
+		printf("ERROR: PCM verification requires 1 or 2 channels, got %u\n", channels);
+		return false;
+	}
+	if(bps != 8 && bps != 16) {
+		printf("ERROR: PCM verification requires 8 or 16 bps, got %u\n", bps);
+		return false;
+	}
+	samples = rawfilesize / channels / (bps>>3);
+	if (samples > 10000000) {
+		fprintf(stderr, "ERROR: %s is too big\n", rawfilename);
+		return false;
+	}
+	for(i = 0; i < channels; i++) {
+		if(0 == (pcm[i] = malloc(sizeof(FLAC__int32)*samples))) {
+			printf("ERROR: allocating space for PCM samples\n");
+			return false;
+		}
+	}
+	if(0 == (f = flac_fopen(rawfilename, "rb"))) {
+		printf("ERROR: opening %s for reading\n", rawfilename);
+		return false;
+	}
+	/* assumes signed big-endian data */
+	if(bps == 8) {
+		signed char c;
+		for(i = 0; i < samples; i++) {
+			for(j = 0; j < channels; j++) {
+				if (fread(&c, 1, 1, f) == 1)
+					pcm[j][i] = c;
+			}
+		}
+	}
+	else { /* bps == 16 */
+		uint8_t c[2];
+		uint16_t value;
+		for(i = 0; i < samples; i++) {
+			for(j = 0; j < channels; j++) {
+				if (fread(&c, 1, 2, f) == 2) {
+					value = (c[0] << 8) | c[1];
+					pcm[j][i] = value & 0x8000 ? 0xffff0000 | value : value;
+				}
+			}
+		}
+	}
+	fclose(f);
+	return true;
+}
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+	(void)decoder, (void)buffer;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in write callback is NULL\n");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	if(dcd->error_occurred)
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+	FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); /* decoder guarantees this */
+	if (!dcd->quiet)
+		printf("frame@%" PRIu64 "(%u)... ", frame->header.number.sample_number, frame->header.blocksize);
+	fflush(stdout);
+
+	/* check against PCM data if we have it */
+	if (dcd->pcm) {
+		uint32_t c, i, j;
+		for (c = 0; c < frame->header.channels; c++)
+			for (i = (uint32_t)frame->header.number.sample_number, j = 0; j < frame->header.blocksize; i++, j++)
+				if (buffer[c][j] != dcd->pcm[c][i]) {
+					printf("ERROR: sample mismatch at sample#%u(%u), channel=%u, expected %d, got %d\n", i, j, c, buffer[c][j], dcd->pcm[c][i]);
+					return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+				}
+	}
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in metadata callback is NULL\n");
+		return;
+	}
+
+	if(dcd->error_occurred)
+		return;
+
+	if (!dcd->got_data && metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		dcd->got_data = true;
+		dcd->total_samples = metadata->data.stream_info.total_samples;
+		dcd->channels = metadata->data.stream_info.channels;
+		dcd->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+	}
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+	(void)decoder;
+
+	if(0 == dcd) {
+		printf("ERROR: client_data in error callback is NULL\n");
+		return;
+	}
+
+	if(!dcd->ignore_errors) {
+		printf("ERROR: got error callback: err = %u (%s)\n", (uint32_t)status, FLAC__StreamDecoderErrorStatusString[status]);
+		dcd->error_occurred = true;
+	}
+}
+
+/* read mode:
+ * 0 - no read after seek
+ * 1 - read 2 frames
+ * 2 - read until end
+ */
+static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, FLAC__off_t filesize, uint32_t count, FLAC__int64 total_samples, uint32_t read_mode, FLAC__int32 **pcm)
+{
+	FLAC__StreamDecoder *decoder;
+	DecoderClientData decoder_client_data;
+	uint32_t i;
+	long int n;
+
+	decoder_client_data.pcm = pcm;
+	decoder_client_data.got_data = false;
+	decoder_client_data.total_samples = 0;
+	decoder_client_data.quiet = false;
+	decoder_client_data.ignore_errors = false;
+	decoder_client_data.error_occurred = false;
+
+	printf("\n+++ seek test: FLAC__StreamDecoder (%s FLAC, read_mode=%u)\n\n", is_ogg? "Ogg":"native", read_mode);
+
+	decoder = FLAC__stream_decoder_new();
+	if(0 == decoder)
+		return die_("FLAC__stream_decoder_new() FAILED, returned NULL\n");
+
+	if(is_ogg) {
+		if(FLAC__stream_decoder_init_ogg_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+			return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder);
+	}
+	else {
+		if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+			return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder);
+	}
+
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+		return die_s_("FLAC__stream_decoder_process_until_end_of_metadata() FAILED", decoder);
+
+	if(!is_ogg) { /* not necessary to do this for Ogg because of its seeking method */
+	/* process until end of stream to make sure we can still seek in that state */
+		decoder_client_data.quiet = true;
+		if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+			return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder);
+		decoder_client_data.quiet = false;
+
+		printf("stream decoder state is %s\n", FLAC__stream_decoder_get_resolved_state_string(decoder));
+		if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM)
+			return die_s_("expected FLAC__STREAM_DECODER_END_OF_STREAM", decoder);
+	}
+
+	printf("file's total_samples is %" PRIu64 "\n", decoder_client_data.total_samples);
+	n = (long int)decoder_client_data.total_samples;
+
+	if(n == 0 && total_samples >= 0)
+		n = (long int)total_samples;
+
+	/* if we don't have a total samples count, just guess based on the file size */
+	/* @@@ for is_ogg we should get it from last page's granulepos */
+	if(n == 0) {
+		/* 8 would imply no compression, 9 guarantees that we will get some samples off the end of the stream to test that case */
+		n = 9 * filesize / (decoder_client_data.channels * decoder_client_data.bits_per_sample);
+	}
+
+	printf("Begin seek barrage, count=%u\n", count);
+
+	for (i = 0; !stop_signal_ && (count == 0 || i < count); i++) {
+		FLAC__uint64 pos;
+
+		/* for the first 10, seek to the first 10 samples */
+		if (n >= 10 && i < 10) {
+			pos = i;
+		}
+		/* for the second 10, seek to the last 10 samples */
+		else if (n >= 10 && i < 20) {
+			pos = n - 1 - (i-10);
+		}
+		/* for the third 10, seek past the end and make sure we fail properly as expected */
+		else if (i < 30) {
+			pos = n + (i-20);
+		}
+		else {
+			pos = (FLAC__uint64)(local_rand_() % n);
+		}
+
+		printf("#%u:seek(%" PRIu64 ")... ", i, pos);
+		fflush(stdout);
+		if(!FLAC__stream_decoder_seek_absolute(decoder, pos)) {
+			if(pos >= (FLAC__uint64)n)
+				printf("seek past end failed as expected... ");
+			else if(decoder_client_data.total_samples == 0 && total_samples <= 0)
+				printf("seek failed, assuming it was past EOF... ");
+			else
+				return die_s_("FLAC__stream_decoder_seek_absolute() FAILED", decoder);
+			if(!FLAC__stream_decoder_flush(decoder))
+				return die_s_("FLAC__stream_decoder_flush() FAILED", decoder);
+		}
+		else if(read_mode == 1) {
+			printf("decode_frame... ");
+			fflush(stdout);
+			if(!FLAC__stream_decoder_process_single(decoder))
+				return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder);
+
+			printf("decode_frame... ");
+			fflush(stdout);
+			if(!FLAC__stream_decoder_process_single(decoder))
+				return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder);
+		}
+		else if(read_mode == 2) {
+			printf("decode_all... ");
+			fflush(stdout);
+			decoder_client_data.quiet = true;
+			if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+				return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder);
+			decoder_client_data.quiet = false;
+		}
+
+		printf("OK\n");
+		fflush(stdout);
+	}
+	stop_signal_ = false;
+
+	if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) {
+		if(!FLAC__stream_decoder_finish(decoder))
+			return die_s_("FLAC__stream_decoder_finish() FAILED", decoder);
+	}
+
+	FLAC__stream_decoder_delete(decoder);
+	printf("\nPASSED!\n");
+
+	return true;
+}
+
+
+int main(int argc, char *argv[])
+{
+	const char *flacfilename, *rawfilename = 0;
+	uint32_t count = 0, read_mode;
+	FLAC__int64 samples = -1;
+	FLAC__off_t flacfilesize;
+	FLAC__int32 *pcm[2] = { 0, 0 };
+	FLAC__bool ok = true;
+
+	static const char * const usage = "usage: test_seeking file.flac [#seeks] [#samples-in-file.flac] [file.raw]\n";
+
+	if (argc < 2 || argc > 5) {
+		fputs(usage, stderr);
+		return 1;
+	}
+
+	flacfilename = argv[1];
+
+	if (argc > 2)
+		count = strtoul(argv[2], 0, 10);
+	if (argc > 3)
+		samples = strtoull(argv[3], 0, 10);
+	if (argc > 4)
+		rawfilename = argv[4];
+
+	if (count < 30)
+		fprintf(stderr, "WARNING: random seeks don't kick in until after 30 preprogrammed ones\n");
+
+#if !defined _MSC_VER && !defined __MINGW32__
+	{
+		struct timeval tv;
+
+		if (gettimeofday(&tv, 0) < 0) {
+			fprintf(stderr, "WARNING: couldn't seed RNG with time\n");
+			tv.tv_usec = 4321;
+		}
+		srandom(tv.tv_usec);
+	}
+#else
+	srand((uint32_t)time(0));
+#endif
+
+	flacfilesize = get_filesize_(flacfilename);
+	if (flacfilesize < 0) {
+		fprintf(stderr, "ERROR: can't determine filesize for %s\n", flacfilename);
+		return 1;
+	}
+
+	if (rawfilename && !read_pcm_(pcm, rawfilename, flacfilename)) {
+		free(pcm[0]);
+		free(pcm[1]);
+		return 1;
+	}
+
+	(void) signal(SIGINT, our_sigint_handler_);
+
+	for (read_mode = 0; ok && read_mode <= 2; read_mode++) {
+		/* no need to do "decode all" read_mode if PCM checking is available */
+		if (rawfilename && read_mode > 1)
+			continue;
+		if (strlen(flacfilename) > 4 && (0 == strcmp(flacfilename+strlen(flacfilename)-4, ".oga") || 0 == strcmp(flacfilename+strlen(flacfilename)-4, ".ogg"))) {
+#if FLAC__HAS_OGG
+			ok = seek_barrage(/*is_ogg=*/true, flacfilename, flacfilesize, count, samples, read_mode, rawfilename? pcm : 0);
+#else
+			fprintf(stderr, "ERROR: Ogg FLAC not supported\n");
+			ok = false;
+#endif
+		}
+		else {
+			ok = seek_barrage(/*is_ogg=*/false, flacfilename, flacfilesize, count, samples, read_mode, rawfilename? pcm : 0);
+		}
+	}
+
+	free(pcm[0]);
+	free(pcm[1]);
+
+	return ok? 0 : 2;
+}
diff --git a/src/test_seeking/test_seeking.vcproj b/src/test_seeking/test_seeking.vcproj
new file mode 100644
index 0000000..bcfe310
--- /dev/null
+++ b/src/test_seeking/test_seeking.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="test_seeking"

+	ProjectGUID="{4cefbc90-c215-11db-8314-0800200c9a66}"

+	RootNamespace="test_seeking"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/test_seeking/test_seeking.vcxproj b/src/test_seeking/test_seeking.vcxproj
new file mode 100644
index 0000000..cc20367
--- /dev/null
+++ b/src/test_seeking/test_seeking.vcxproj
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc90-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>test_seeking</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_seeking/test_seeking.vcxproj.filters b/src/test_seeking/test_seeking.vcxproj.filters
new file mode 100644
index 0000000..5c9040b
--- /dev/null
+++ b/src/test_seeking/test_seeking.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_streams/CMakeLists.txt b/src/test_streams/CMakeLists.txt
new file mode 100644
index 0000000..f9fafb9
--- /dev/null
+++ b/src/test_streams/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(test_streams main.c)
+target_link_libraries(test_streams FLAC grabbag)
diff --git a/src/test_streams/Makefile.am b/src/test_streams/Makefile.am
new file mode 100644
index 0000000..ef444ae
--- /dev/null
+++ b/src/test_streams/Makefile.am
@@ -0,0 +1,33 @@
+#  test_streams - Simple test pattern generator
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	test_streams.vcproj \
+	test_streams.vcxproj \
+	test_streams.vcxproj.filters
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+check_PROGRAMS = test_streams
+test_streams_SOURCES = \
+	main.c
+
+test_streams_LDADD = $(top_builddir)/src/share/grabbag/libgrabbag.la -lm
+
+CLEANFILES = test_streams.exe
diff --git a/src/test_streams/Makefile.lite b/src/test_streams/Makefile.lite
new file mode 100644
index 0000000..1e87c37
--- /dev/null
+++ b/src/test_streams/Makefile.lite
@@ -0,0 +1,43 @@
+#  test_streams - Simple test pattern generator
+#  Copyright (C) 2000-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+include $(topdir)/build/config.mk
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = test_streams
+
+INCLUDES = -I./include -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a -lm
+else
+    LIBS = -lgrabbag -lreplaygain_analysis -lm
+endif
+
+SRCS_C = \
+	main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_streams/main.c b/src/test_streams/main.c
new file mode 100644
index 0000000..7f21fe0
--- /dev/null
+++ b/src/test_streams/main.c
@@ -0,0 +1,1284 @@
+/* test_streams - Simple test pattern generator
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "share/compat.h"
+#if defined _MSC_VER || defined __MINGW32__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#include "FLAC/assert.h"
+#include "FLAC/ordinals.h"
+#include "share/compat.h"
+
+#if !defined _MSC_VER && !defined __MINGW32__
+#define GET_RANDOM_BYTE (((unsigned)random()) & 0xff)
+#else
+#define GET_RANDOM_BYTE (((unsigned)rand()) & 0xff)
+#endif
+
+static FLAC__bool is_big_endian_host;
+
+
+static FLAC__bool write_little_endian_unsigned(FILE *f, FLAC__uint32 x, size_t bytes)
+{
+	while(bytes) {
+		if(fputc(x, f) == EOF)
+			return false;
+		x >>= 8;
+		bytes--;
+	}
+	return true;
+}
+
+static FLAC__bool write_little_endian_signed(FILE *f, FLAC__int32 x, size_t bytes)
+{
+	return write_little_endian_unsigned(f, (FLAC__uint32) x, bytes);
+}
+
+static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+	return
+		fputc(x, f) != EOF &&
+		fputc(x >> 8, f) != EOF
+	;
+}
+
+static FLAC__bool write_little_endian_int16(FILE *f, FLAC__int16 x)
+{
+	return write_little_endian_uint16(f, (FLAC__uint16)x);
+}
+
+static FLAC__bool write_little_endian_uint24(FILE *f, FLAC__uint32 x)
+{
+	return
+		fputc(x, f) != EOF &&
+		fputc(x >> 8, f) != EOF &&
+		fputc(x >> 16, f) != EOF
+	;
+}
+
+static FLAC__bool write_little_endian_int24(FILE *f, FLAC__int32 x)
+{
+	return write_little_endian_uint24(f, (FLAC__uint32)x);
+}
+
+static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+	return
+		fputc(x, f) != EOF &&
+		fputc(x >> 8, f) != EOF &&
+		fputc(x >> 16, f) != EOF &&
+		fputc(x >> 24, f) != EOF
+	;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_little_endian_int32(FILE *f, FLAC__int32 x)
+{
+	return write_little_endian_uint32(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_little_endian_uint64(FILE *f, FLAC__uint64 x)
+{
+	return
+		fputc(x, f) != EOF &&
+		fputc(x >> 8, f) != EOF &&
+		fputc(x >> 16, f) != EOF &&
+		fputc(x >> 24, f) != EOF &&
+		fputc(x >> 32, f) != EOF &&
+		fputc(x >> 40, f) != EOF &&
+		fputc(x >> 48, f) != EOF &&
+		fputc(x >> 56, f) != EOF
+	;
+}
+
+static FLAC__bool write_big_endian(FILE *f, FLAC__int32 x, size_t bytes)
+{
+	if(bytes < 4)
+		x <<= 8*(4-bytes);
+	while(bytes) {
+		if(fputc(x>>24, f) == EOF)
+			return false;
+		x <<= 8;
+		bytes--;
+	}
+	return true;
+}
+
+static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+	return
+		fputc(x >> 8, f) != EOF &&
+		fputc(x, f) != EOF
+	;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int16(FILE *f, FLAC__int16 x)
+{
+	return write_big_endian_uint16(f, (FLAC__uint16)x);
+}
+#endif
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_uint24(FILE *f, FLAC__uint32 x)
+{
+	return
+		fputc(x >> 16, f) != EOF &&
+		fputc(x >> 8, f) != EOF &&
+		fputc(x, f) != EOF
+	;
+}
+#endif
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int24(FILE *f, FLAC__int32 x)
+{
+	return write_big_endian_uint24(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+	return
+		fputc(x >> 24, f) != EOF &&
+		fputc(x >> 16, f) != EOF &&
+		fputc(x >> 8, f) != EOF &&
+		fputc(x, f) != EOF
+	;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int32(FILE *f, FLAC__int32 x)
+{
+	return write_big_endian_uint32(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_sane_extended(FILE *f, unsigned val)
+	/* Write to 'f' a SANE extended representation of 'val'.  Return false if
+	* the write succeeds; return true otherwise.
+	*
+	* SANE extended is an 80-bit IEEE-754 representation with sign bit, 15 bits
+	* of exponent, and 64 bits of significand (mantissa).  Unlike most IEEE-754
+	* representations, it does not imply a 1 above the MSB of the significand.
+	*
+	* Preconditions:
+	*  val!=0U
+	*/
+{
+	unsigned int shift, exponent;
+
+	FLAC__ASSERT(val!=0U); /* handling 0 would require a special case */
+
+	for(shift= 0U; (val>>(31-shift))==0U; ++shift)
+		;
+	val<<= shift;
+	exponent= 63U-(shift+32U); /* add 32 for unused second word */
+
+	if(!write_big_endian_uint16(f, (FLAC__uint16)(exponent+0x3FFF)))
+		return false;
+	if(!write_big_endian_uint32(f, val))
+		return false;
+	if(!write_big_endian_uint32(f, 0)) /* unused second word */
+		return false;
+
+	return true;
+}
+
+/* a mono one-sample 16bps stream */
+static FLAC__bool generate_01(void)
+{
+	FILE *f;
+	FLAC__int16 x = -32768;
+
+	if(0 == (f = fopen("test01.raw", "wb")))
+		return false;
+
+	if(!write_little_endian_int16(f, x))
+		goto foo;
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a stereo one-sample 16bps stream */
+static FLAC__bool generate_02(void)
+{
+	FILE *f;
+	FLAC__int16 xl = -32768, xr = 32767;
+
+	if(0 == (f = fopen("test02.raw", "wb")))
+		return false;
+
+	if(!write_little_endian_int16(f, xl))
+		goto foo;
+	if(!write_little_endian_int16(f, xr))
+		goto foo;
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a mono five-sample 16bps stream */
+static FLAC__bool generate_03(void)
+{
+	FILE *f;
+	FLAC__int16 x[] = { -25, 0, 25, 50, 100 };
+	unsigned i;
+
+	if(0 == (f = fopen("test03.raw", "wb")))
+		return false;
+
+	for(i = 0; i < 5; i++)
+		if(!write_little_endian_int16(f, x[i]))
+			goto foo;
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a stereo five-sample 16bps stream */
+static FLAC__bool generate_04(void)
+{
+	FILE *f;
+	FLAC__int16 x[] = { -25, 500, 0, 400, 25, 300, 50, 200, 100, 100 };
+	unsigned i;
+
+	if(0 == (f = fopen("test04.raw", "wb")))
+		return false;
+
+	for(i = 0; i < 10; i++)
+		if(!write_little_endian_int16(f, x[i]))
+			goto foo;
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a mono full-scale deflection 8bps stream */
+static FLAC__bool generate_fsd8(const char *fn, const int pattern[], unsigned reps)
+{
+	FILE *f;
+	unsigned rep, p;
+
+	FLAC__ASSERT(pattern != 0);
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(rep = 0; rep < reps; rep++) {
+		for(p = 0; pattern[p]; p++) {
+			signed char x = pattern[p] > 0? 127 : -128;
+			if(fwrite(&x, sizeof(x), 1, f) < 1)
+				goto foo;
+		}
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a mono full-scale deflection 16bps stream */
+static FLAC__bool generate_fsd16(const char *fn, const int pattern[], unsigned reps)
+{
+	FILE *f;
+	unsigned rep, p;
+
+	FLAC__ASSERT(pattern != 0);
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(rep = 0; rep < reps; rep++) {
+		for(p = 0; pattern[p]; p++) {
+			FLAC__int16 x = pattern[p] > 0? 32767 : -32768;
+			if(!write_little_endian_int16(f, x))
+				goto foo;
+		}
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a stereo wasted-bits-per-sample 16bps stream */
+static FLAC__bool generate_wbps16(const char *fn, unsigned samples)
+{
+	FILE *f;
+	unsigned sample;
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(sample = 0; sample < samples; sample++) {
+		FLAC__int16 l = (sample % 2000) << 2;
+		FLAC__int16 r = (sample % 1000) << 3;
+		if(!write_little_endian_int16(f, l))
+			goto foo;
+		if(!write_little_endian_int16(f, r))
+			goto foo;
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a mono full-scale deflection 24bps stream */
+static FLAC__bool generate_fsd24(const char *fn, const int pattern[], unsigned reps)
+{
+	FILE *f;
+	unsigned rep, p;
+
+	FLAC__ASSERT(pattern != 0);
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(rep = 0; rep < reps; rep++) {
+		for(p = 0; pattern[p]; p++) {
+			FLAC__int32 x = pattern[p] > 0? 8388607 : -8388608;
+			if(!write_little_endian_int24(f, x))
+				goto foo;
+		}
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a mono sine-wave 8bps stream */
+static FLAC__bool generate_sine8_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+	const FLAC__int8 full_scale = 127;
+	const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+	const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+	FILE *f;
+	double theta1, theta2;
+	unsigned i;
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+		FLAC__int8 v = (FLAC__int8)(val + 0.5);
+		if(fwrite(&v, sizeof(v), 1, f) < 1)
+			goto foo;
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a stereo sine-wave 8bps stream */
+static FLAC__bool generate_sine8_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+	const FLAC__int8 full_scale = 127;
+	const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+	const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+	FILE *f;
+	double theta1, theta2;
+	unsigned i;
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+		FLAC__int8 v = (FLAC__int8)(val + 0.5);
+		if(fwrite(&v, sizeof(v), 1, f) < 1)
+			goto foo;
+		val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+		v = (FLAC__int8)(val + 0.5);
+		if(fwrite(&v, sizeof(v), 1, f) < 1)
+			goto foo;
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a mono sine-wave 16bps stream */
+static FLAC__bool generate_sine16_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+	const FLAC__int16 full_scale = 32767;
+	const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+	const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+	FILE *f;
+	double theta1, theta2;
+	unsigned i;
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+		FLAC__int16 v = (FLAC__int16)(val + 0.5);
+		if(!write_little_endian_int16(f, v))
+			goto foo;
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a stereo sine-wave 16bps stream */
+static FLAC__bool generate_sine16_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+	const FLAC__int16 full_scale = 32767;
+	const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+	const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+	FILE *f;
+	double theta1, theta2;
+	unsigned i;
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+		FLAC__int16 v = (FLAC__int16)(val + 0.5);
+		if(!write_little_endian_int16(f, v))
+			goto foo;
+		val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+		v = (FLAC__int16)(val + 0.5);
+		if(!write_little_endian_int16(f, v))
+			goto foo;
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a mono sine-wave 24bps stream */
+static FLAC__bool generate_sine24_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+	const FLAC__int32 full_scale = 0x7fffff;
+	const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+	const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+	FILE *f;
+	double theta1, theta2;
+	unsigned i;
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+		FLAC__int32 v = (FLAC__int32)(val + 0.5);
+		if(!write_little_endian_int24(f, v))
+			goto foo;
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* a stereo sine-wave 24bps stream */
+static FLAC__bool generate_sine24_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+	const FLAC__int32 full_scale = 0x7fffff;
+	const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+	const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+	FILE *f;
+	double theta1, theta2;
+	unsigned i;
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+		FLAC__int32 v = (FLAC__int32)(val + 0.5);
+		if(!write_little_endian_int24(f, v))
+			goto foo;
+		val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+		v = (FLAC__int32)(val + 0.5);
+		if(!write_little_endian_int24(f, v))
+			goto foo;
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool generate_noise(const char *fn, unsigned bytes)
+{
+	FILE *f;
+	unsigned b;
+
+	if(0 == (f = fopen(fn, "wb")))
+		return false;
+
+	for(b = 0; b < bytes; b++) {
+#if !defined _MSC_VER && !defined __MINGW32__
+		FLAC__byte x = (FLAC__byte)(((unsigned)random()) & 0xff);
+#else
+		FLAC__byte x = (FLAC__byte)(((unsigned)rand()) & 0xff);
+#endif
+		if(fwrite(&x, sizeof(x), 1, f) < 1)
+			goto foo;
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool generate_signed_raw(const char *filename, unsigned channels, unsigned bytes_per_sample, unsigned samples)
+{
+	const FLAC__int32 full_scale = (1 << (bytes_per_sample*8-1)) - 1;
+	const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+	const double delta1 = 2.0 * M_PI / ( 44100.0 / f1);
+	const double delta2 = 2.0 * M_PI / ( 44100.0 / f2);
+	double theta1, theta2;
+	FILE *f;
+	unsigned i, j;
+
+	if(0 == (f = fopen(filename, "wb")))
+		return false;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		for(j = 0; j < channels; j++) {
+			double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+			FLAC__int32 v = (FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8);
+			if(!write_little_endian_signed(f, v, bytes_per_sample))
+				goto foo;
+		}
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool generate_unsigned_raw(const char *filename, unsigned channels, unsigned bytes_per_sample, unsigned samples)
+{
+	const FLAC__int32 full_scale = (1 << (bytes_per_sample*8-1)) - 1;
+	const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+	const double delta1 = 2.0 * M_PI / ( 44100.0 / f1);
+	const double delta2 = 2.0 * M_PI / ( 44100.0 / f2);
+	const double half_scale = 0.5 * full_scale;
+	double theta1, theta2;
+	FILE *f;
+	unsigned i, j;
+
+	if(0 == (f = fopen(filename, "wb")))
+		return false;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		for(j = 0; j < channels; j++) {
+			double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+			FLAC__int32 v = (FLAC__int32)(half_scale + val + 0.5) + ((GET_RANDOM_BYTE>>4)-8);
+			if(!write_little_endian_unsigned(f, v, bytes_per_sample))
+				goto foo;
+		}
+	}
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples)
+{
+	const unsigned bytes_per_sample = (bps+7)/8;
+	const unsigned true_size = channels * bytes_per_sample * samples;
+	const unsigned padded_size = (true_size + 1) & (~1u);
+	const unsigned shift = (bps%8)? 8 - (bps%8) : 0;
+	const FLAC__int32 full_scale = (1 << (bps-1)) - 1;
+	const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+	const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+	const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+	double theta1, theta2;
+	FILE *f;
+	unsigned i, j;
+
+	if(0 == (f = fopen(filename, "wb")))
+		return false;
+	if(fwrite("FORM", 1, 4, f) < 4)
+		goto foo;
+	if(!write_big_endian_uint32(f, padded_size + 46))
+		goto foo;
+	if(fwrite("AIFFCOMM\000\000\000\022", 1, 12, f) < 12)
+		goto foo;
+	if(!write_big_endian_uint16(f, (FLAC__uint16)channels))
+		goto foo;
+	if(!write_big_endian_uint32(f, samples))
+		goto foo;
+	if(!write_big_endian_uint16(f, (FLAC__uint16)bps))
+		goto foo;
+	if(!write_sane_extended(f, sample_rate))
+		goto foo;
+	if(fwrite("SSND", 1, 4, f) < 4)
+		goto foo;
+	if(!write_big_endian_uint32(f, true_size + 8))
+		goto foo;
+	if(fwrite("\000\000\000\000\000\000\000\000", 1, 8, f) < 8)
+		goto foo;
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		for(j = 0; j < channels; j++) {
+			double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+			FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift;
+			if(!write_big_endian(f, v, bytes_per_sample))
+				goto foo;
+		}
+	}
+	for(i = true_size; i < padded_size; i++)
+		if(fputc(0, f) == EOF)
+			goto foo;
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+/* flavor is: 0:WAVE, 1:RF64, 2:WAVE64 */
+static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, FLAC__bool strict, int flavor)
+{
+	const FLAC__bool waveformatextensible = strict && (channels > 2 || (bps != 8 && bps != 16));
+
+	const unsigned bytes_per_sample = (bps+7)/8;
+	const unsigned shift = (bps%8)? 8 - (bps%8) : 0;
+	/* this rig is not going over 4G so we're ok with 32-bit sizes here */
+	const FLAC__uint32 true_size = channels * bytes_per_sample * samples;
+	const FLAC__uint32 padded_size = flavor<2? (true_size + 1) & (~1u) : (true_size + 7) & (~7u);
+	const FLAC__int32 full_scale = (1 << (bps-1)) - 1;
+	const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+	const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+	const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+	double theta1, theta2;
+	FILE *f;
+	unsigned i, j;
+
+	if(0 == (f = fopen(filename, "wb")))
+		return false;
+	/* RIFFxxxxWAVE or equivalent: */
+	switch(flavor) {
+		case 0:
+			if(fwrite("RIFF", 1, 4, f) < 4)
+				goto foo;
+			/* +4 for WAVE */
+			/* +8+{40,16} for fmt chunk */
+			/* +8 for data chunk header */
+			if(!write_little_endian_uint32(f, 4 + 8+(waveformatextensible?40:16) + 8 + padded_size))
+				goto foo;
+			if(fwrite("WAVE", 1, 4, f) < 4)
+				goto foo;
+			break;
+		case 1:
+			if(fwrite("RF64", 1, 4, f) < 4)
+				goto foo;
+			if(!write_little_endian_uint32(f, 0xffffffff))
+				goto foo;
+			if(fwrite("WAVE", 1, 4, f) < 4)
+				goto foo;
+			break;
+		case 2:
+			/* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
+			if(fwrite("\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 1, 16, f) < 16)
+				goto foo;
+			/* +(16+8) for RIFF GUID + size */
+			/* +16 for WAVE GUID */
+			/* +16+8+{40,16} for fmt chunk */
+			/* +16+8 for data chunk header */
+			if(!write_little_endian_uint64(f, (16+8) + 16 + 16+8+(waveformatextensible?40:16) + (16+8) + padded_size))
+				goto foo;
+			/* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
+			if(fwrite("\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) < 16)
+				goto foo;
+			break;
+		default:
+			goto foo;
+	}
+	if(flavor == 1) { /* rf64 */
+		if(fwrite("ds64", 1, 4, f) < 4)
+			goto foo;
+		if(!write_little_endian_uint32(f, 28)) /* ds64 chunk size */
+			goto foo;
+		if(!write_little_endian_uint64(f, 36 + padded_size + (waveformatextensible?60:36)))
+			goto foo;
+		if(!write_little_endian_uint64(f, true_size))
+			goto foo;
+		if(!write_little_endian_uint64(f, samples))
+			goto foo;
+		if(!write_little_endian_uint32(f, 0)) /* table size */
+			goto foo;
+	}
+	/* fmt chunk */
+	if(flavor < 2) {
+		if(fwrite("fmt ", 1, 4, f) < 4)
+			goto foo;
+		/* chunk size */
+		if(!write_little_endian_uint32(f, waveformatextensible?40:16))
+			goto foo;
+	}
+	else { /* wave64 */
+		/* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
+		if(fwrite("\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) < 16)
+			goto foo;
+		/* chunk size (+16+8 for GUID and size fields) */
+		if(!write_little_endian_uint64(f, 16+8+(waveformatextensible?40:16)))
+			goto foo;
+	}
+	if(!write_little_endian_uint16(f, (FLAC__uint16)(waveformatextensible?65534:1)))
+		goto foo;
+	if(!write_little_endian_uint16(f, (FLAC__uint16)channels))
+		goto foo;
+	if(!write_little_endian_uint32(f, sample_rate))
+		goto foo;
+	if(!write_little_endian_uint32(f, sample_rate * channels * bytes_per_sample))
+		goto foo;
+	if(!write_little_endian_uint16(f, (FLAC__uint16)(channels * bytes_per_sample))) /* block align */
+		goto foo;
+	if(!write_little_endian_uint16(f, (FLAC__uint16)(bps+shift)))
+		goto foo;
+	if(waveformatextensible) {
+		if(!write_little_endian_uint16(f, (FLAC__uint16)22)) /* cbSize */
+			goto foo;
+		if(!write_little_endian_uint16(f, (FLAC__uint16)bps)) /* validBitsPerSample */
+			goto foo;
+		if(!write_little_endian_uint32(f, 0)) /* channelMask */
+			goto foo;
+		/* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */
+		if(fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16)
+			goto foo;
+	}
+	/* data chunk */
+	if(flavor < 2) {
+		if(fwrite("data", 1, 4, f) < 4)
+			goto foo;
+		if(!write_little_endian_uint32(f, flavor==1? 0xffffffff : true_size))
+			goto foo;
+	}
+	else { /* wave64 */
+		/* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
+		if(fwrite("\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+			goto foo;
+		/* +16+8 for GUID and size fields */
+		if(!write_little_endian_uint64(f, 16+8 + true_size))
+			goto foo;
+	}
+
+	for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+		for(j = 0; j < channels; j++) {
+			double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+			FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift;
+			if(!write_little_endian_signed(f, v, bytes_per_sample))
+				goto foo;
+		}
+	}
+	for(i = true_size; i < padded_size; i++)
+		if(fputc(0, f) == EOF)
+			goto foo;
+
+	fclose(f);
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool generate_wackywavs(void)
+{
+	FILE *f;
+	FLAC__byte wav[] = {
+		'R', 'I', 'F', 'F',  76,   0,   0,   0,
+		'W', 'A', 'V', 'E', 'j', 'u', 'n', 'k',
+		  4,   0,   0,  0 , 'b', 'l', 'a', 'h',
+		'p', 'a', 'd', ' ',   4,   0,   0,   0,
+		'B', 'L', 'A', 'H', 'f', 'm', 't', ' ',
+		 16,   0,   0,   0,   1,   0,   1,   0,
+		0x44,0xAC,  0,   0,0x88,0x58,0x01,   0,
+		  2,   0,  16,   0, 'd', 'a', 't', 'a',
+		 16,   0,   0,   0,   0,   0,   1,   0,
+		  4,   0,   9,   0,  16,   0,  25,   0,
+		 36,   0,  49,   0, 'p', 'a', 'd', ' ',
+		  4,   0,   0,   0, 'b', 'l', 'a', 'h'
+	};
+
+	if(0 == (f = fopen("wacky1.wav", "wb")))
+		return false;
+	if(fwrite(wav, 1, 84, f) < 84)
+		goto foo;
+	fclose(f);
+
+	wav[4] += 12;
+	if(0 == (f = fopen("wacky2.wav", "wb")))
+		return false;
+	if(fwrite(wav, 1, 96, f) < 96)
+		goto foo;
+	fclose(f);
+
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool write_simple_wavex_header (FILE * f, unsigned samplerate, unsigned channels, unsigned bytespersample, unsigned frames)
+{
+	unsigned datalen = channels * bytespersample * frames ;
+
+	if (fwrite("RIFF", 1, 4, f) != 4)
+		return false;
+	if (!write_little_endian_uint32(f, 40 + 4 + 4 + datalen))
+		return false;
+
+	if (fwrite("WAVEfmt ", 8, 1, f) != 1)
+		return false;
+	if (!write_little_endian_uint32(f, 40))
+		return false;
+
+	if(!write_little_endian_uint16(f, 65534)) /* WAVEFORMATEXTENSIBLE tag */
+		return false;
+	if(!write_little_endian_uint16(f, channels))
+		return false;
+	if(!write_little_endian_uint32(f, samplerate))
+		return false;
+	if(!write_little_endian_uint32(f, samplerate * channels * bytespersample))
+		return false;
+	if(!write_little_endian_uint16(f, channels * bytespersample)) /* block align */
+		return false;
+	if(!write_little_endian_uint16(f, bytespersample * 8))
+		return false;
+
+	if(!write_little_endian_uint16(f, 22)) /* cbSize */
+		return false;
+	if(!write_little_endian_uint16(f, bytespersample * 8)) /* validBitsPerSample */
+		return false;
+	if(!write_little_endian_uint32(f, 0)) /* channelMask */
+		return false;
+	/* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */
+	if(fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16)
+		return false;
+
+	if (fwrite("data", 1, 4, f) != 4)
+		return false;
+	if (!write_little_endian_uint32(f, datalen))
+		return false;
+
+	return true;
+}
+
+static FLAC__bool generate_noisy_sine(void)
+{
+	FILE *f;
+	int64_t randstate = 0x1243456;
+	double sample, last_val = 0.0;
+	int k;
+
+	if(0 == (f = fopen("noisy-sine.wav", "wb")))
+		return false;
+
+	if(!write_simple_wavex_header (f, 44100, 1, 2, 220500))
+		goto foo;
+
+	for (k = 0 ; k < 5 * 44100 ; k++) {
+		/* Obvioulsy not a crypto quality RNG. */
+		randstate = 11117 * randstate + 211231;
+		randstate = 11117 * randstate + 211231;
+		randstate = 11117 * randstate + 211231;
+
+		sample = ((int32_t) randstate) / (0x7fffffff * 1.000001);
+		sample = 0.2 * sample - 0.9 * last_val;
+
+		last_val = sample;
+
+		sample += sin (2.0 * k * M_PI * 1.0 / 32.0);
+		sample *= 0.4;
+#if !defined _MSC_VER
+		write_little_endian_int16(f, lrintf(sample * 32700.0));
+#else
+		write_little_endian_int16(f, (FLAC__int16)(sample * 32700.0));
+#endif
+	};
+
+	fclose(f);
+
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool generate_wackywav64s(void)
+{
+	FILE *f;
+	FLAC__byte wav[] = {
+		0x72,0x69,0x66,0x66,0x2E,0x91,0xCF,0x11, /* RIFF GUID */
+		0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00,
+		 152,   0,   0,   0,   0,   0,   0,   0,
+		0x77,0x61,0x76,0x65,0xF3,0xAC,0xD3,0x11, /* WAVE GUID */
+		0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+		0x6A,0x75,0x6E,0x6B,0xF3,0xAC,0xD3,0x11, /* junk GUID */
+		0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+		  32,   0,   0,  0 ,   0,   0,   0,   0,
+		 'b', 'l', 'a', 'h', 'b', 'l', 'a', 'h',
+		0x66,0x6D,0x74,0x20,0xF3,0xAC,0xD3,0x11, /* fmt GUID */
+		0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+		  40,   0,   0,  0 ,   0,   0,   0,   0,
+		   1,   0,   1,   0,0x44,0xAC,   0,   0,
+		0x88,0x58,0x01,   0,   2,   0,  16,   0,
+		0x64,0x61,0x74,0x61,0xF3,0xAC,0xD3,0x11, /* data GUID */
+		0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+		  40,   0,   0,  0 ,   0,   0,   0,   0,
+		   0,   0,   1,   0,   4,   0,   9,   0,
+		  16,   0,  25,   0,  36,   0,  49,   0,
+		0x6A,0x75,0x6E,0x6B,0xF3,0xAC,0xD3,0x11, /* junk GUID */
+		0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+		  32,   0,   0,  0 ,   0,   0,   0,   0,
+		 'b', 'l', 'a', 'h', 'b', 'l', 'a', 'h'
+	};
+
+	if(0 == (f = fopen("wacky1.w64", "wb")))
+		return false;
+	if(fwrite(wav, 1, wav[16], f) < wav[16])
+		goto foo;
+	fclose(f);
+
+	wav[16] += 32;
+	if(0 == (f = fopen("wacky2.w64", "wb")))
+		return false;
+	if(fwrite(wav, 1, wav[16], f) < wav[16])
+		goto foo;
+	fclose(f);
+
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool generate_wackyrf64s(void)
+{
+	FILE *f;
+	FLAC__byte wav[] = {
+		'R', 'F', '6', '4', 255, 255, 255, 255,
+		'W', 'A', 'V', 'E', 'd', 's', '6', '4',
+		 28,   0,   0,   0, 112,   0,   0,   0,
+		  0,   0,   0,   0,  16,   0,   0,   0,
+		  0,   0,   0,   0,   8,   0,   0,   0,
+		  0,   0,   0,   0,   0,   0,   0,   0,
+		                    'j', 'u', 'n', 'k',
+		  4,   0,   0,   0, 'b', 'l', 'a', 'h',
+		'p', 'a', 'd', ' ',   4,   0,   0,   0,
+		'B', 'L', 'A', 'H', 'f', 'm', 't', ' ',
+		 16,   0,   0,   0,   1,   0,   1,   0,
+		0x44,0xAC,  0,   0,0x88,0x58,0x01,   0,
+		  2,   0,  16,   0, 'd', 'a', 't', 'a',
+		255, 255, 255, 255,   0,   0,   1,   0,
+		  4,   0,   9,   0,  16,   0,  25,   0,
+		 36,   0,  49,   0, 'p', 'a', 'd', ' ',
+		  4,   0,   0,   0, 'b', 'l', 'a', 'h'
+	};
+
+	if(0 == (f = fopen("wacky1.rf64", "wb")))
+		return false;
+	if(fwrite(wav, 1, 120, f) < 120)
+		goto foo;
+	fclose(f);
+
+	wav[20] += 12;
+	if(0 == (f = fopen("wacky2.rf64", "wb")))
+		return false;
+	if(fwrite(wav, 1, 132, f) < 132)
+		goto foo;
+	fclose(f);
+
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+static FLAC__bool generate_replaygain_tone (unsigned samplerate)
+{
+	FILE *f;
+	char fname [256] ;
+	double tone, sample, samplerange;
+	int k;
+
+	flac_snprintf(fname, sizeof(fname), "rpg-tone-%u.wav", samplerate);
+
+	if(0 == (f = fopen(fname, "wb")))
+		return false;
+
+	if(!write_simple_wavex_header (f, samplerate, 1, 3, 220500))
+		goto foo;
+
+
+	samplerange = 0x7fffff; /* Largest sample value allowed for a 24 bit PCM file. */
+	tone = 1000.0; /* 1 kHz */
+
+	for (k = 0 ; k < 5 * 44100 ; k++) {
+		sample = sin(2 * M_PI * tone * k / samplerate);
+		sample *= samplerange;
+		if (!write_little_endian_uint24(f, (FLAC__int32) sample))
+			goto foo;
+	};
+
+	fclose(f);
+
+	return true;
+foo:
+	fclose(f);
+	return false;
+}
+
+int main(int argc, char *argv[])
+{
+	FLAC__uint32 test = 1;
+	unsigned channels;
+
+	int pattern01[] = { 1, -1, 0 };
+	int pattern02[] = { 1, 1, -1, 0 };
+	int pattern03[] = { 1, -1, -1, 0 };
+	int pattern04[] = { 1, -1, 1, -1, 0 };
+	int pattern05[] = { 1, -1, -1, 1, 0 };
+	int pattern06[] = { 1, -1, 1, 1, -1, 0 };
+	int pattern07[] = { 1, -1, -1, 1, -1, 0 };
+
+	(void)argc;
+	(void)argv;
+	is_big_endian_host = (*((FLAC__byte*)(&test)))? false : true;
+
+#if !defined _MSC_VER && !defined __MINGW32__
+	{
+		struct timeval tv;
+
+		if(gettimeofday(&tv, 0) < 0) {
+			fprintf(stderr, "WARNING: couldn't seed RNG with time\n");
+			tv.tv_usec = 4321;
+		}
+		srandom(tv.tv_usec);
+	}
+#else
+	srand((unsigned)time(0));
+#endif
+
+	if(!generate_01()) return 1;
+	if(!generate_02()) return 1;
+	if(!generate_03()) return 1;
+	if(!generate_04()) return 1;
+
+	if(!generate_fsd8("fsd8-01.raw", pattern01, 100)) return 1;
+	if(!generate_fsd8("fsd8-02.raw", pattern02, 100)) return 1;
+	if(!generate_fsd8("fsd8-03.raw", pattern03, 100)) return 1;
+	if(!generate_fsd8("fsd8-04.raw", pattern04, 100)) return 1;
+	if(!generate_fsd8("fsd8-05.raw", pattern05, 100)) return 1;
+	if(!generate_fsd8("fsd8-06.raw", pattern06, 100)) return 1;
+	if(!generate_fsd8("fsd8-07.raw", pattern07, 100)) return 1;
+
+	if(!generate_fsd16("fsd16-01.raw", pattern01, 100)) return 1;
+	if(!generate_fsd16("fsd16-02.raw", pattern02, 100)) return 1;
+	if(!generate_fsd16("fsd16-03.raw", pattern03, 100)) return 1;
+	if(!generate_fsd16("fsd16-04.raw", pattern04, 100)) return 1;
+	if(!generate_fsd16("fsd16-05.raw", pattern05, 100)) return 1;
+	if(!generate_fsd16("fsd16-06.raw", pattern06, 100)) return 1;
+	if(!generate_fsd16("fsd16-07.raw", pattern07, 100)) return 1;
+
+	if(!generate_fsd24("fsd24-01.raw", pattern01, 100)) return 1;
+	if(!generate_fsd24("fsd24-02.raw", pattern02, 100)) return 1;
+	if(!generate_fsd24("fsd24-03.raw", pattern03, 100)) return 1;
+	if(!generate_fsd24("fsd24-04.raw", pattern04, 100)) return 1;
+	if(!generate_fsd24("fsd24-05.raw", pattern05, 100)) return 1;
+	if(!generate_fsd24("fsd24-06.raw", pattern06, 100)) return 1;
+	if(!generate_fsd24("fsd24-07.raw", pattern07, 100)) return 1;
+
+	if(!generate_wbps16("wbps16-01.raw", 1000)) return 1;
+
+	if(!generate_sine8_1("sine8-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+	if(!generate_sine8_1("sine8-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+	if(!generate_sine8_1("sine8-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+	if(!generate_sine8_1("sine8-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+	if(!generate_sine8_1("sine8-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+	if(!generate_sine8_2("sine8-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+	if(!generate_sine8_2("sine8-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+	if(!generate_sine8_2("sine8-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+	if(!generate_sine8_2("sine8-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+	if(!generate_sine8_2("sine8-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+	if(!generate_sine8_2("sine8-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+	if(!generate_sine8_2("sine8-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+	if(!generate_sine8_2("sine8-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+	if(!generate_sine8_2("sine8-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+	if(!generate_sine8_2("sine8-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+	if(!generate_sine16_1("sine16-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+	if(!generate_sine16_1("sine16-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+	if(!generate_sine16_1("sine16-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+	if(!generate_sine16_1("sine16-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+	if(!generate_sine16_1("sine16-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+	if(!generate_sine16_2("sine16-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+	if(!generate_sine16_2("sine16-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+	if(!generate_sine16_2("sine16-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+	if(!generate_sine16_2("sine16-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+	if(!generate_sine16_2("sine16-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+	if(!generate_sine16_2("sine16-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+	if(!generate_sine16_2("sine16-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+	if(!generate_sine16_2("sine16-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+	if(!generate_sine16_2("sine16-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+	if(!generate_sine16_2("sine16-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+	if(!generate_sine24_1("sine24-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+	if(!generate_sine24_1("sine24-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+	if(!generate_sine24_1("sine24-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+	if(!generate_sine24_1("sine24-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+	if(!generate_sine24_1("sine24-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+	if(!generate_sine24_2("sine24-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+	if(!generate_sine24_2("sine24-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+	if(!generate_sine24_2("sine24-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+	if(!generate_sine24_2("sine24-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+	if(!generate_sine24_2("sine24-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+	if(!generate_sine24_2("sine24-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+	if(!generate_sine24_2("sine24-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+	if(!generate_sine24_2("sine24-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+	if(!generate_sine24_2("sine24-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+	if(!generate_sine24_2("sine24-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+	if(!generate_replaygain_tone(8000)) return 1;
+	if(!generate_replaygain_tone(11025)) return 1;
+	if(!generate_replaygain_tone(12000)) return 1;
+	if(!generate_replaygain_tone(16000)) return 1;
+	if(!generate_replaygain_tone(18900)) return 1;
+	if(!generate_replaygain_tone(22050)) return 1;
+	if(!generate_replaygain_tone(24000)) return 1;
+	if(!generate_replaygain_tone(28000)) return 1;
+	if(!generate_replaygain_tone(32000)) return 1;
+	if(!generate_replaygain_tone(36000)) return 1;
+	if(!generate_replaygain_tone(37800)) return 1;
+	if(!generate_replaygain_tone(44100)) return 1;
+	if(!generate_replaygain_tone(48000)) return 1;
+	if(!generate_replaygain_tone(96000)) return 1;
+	if(!generate_replaygain_tone(192000)) return 1;
+
+	/* WATCHOUT: the size of noise.raw is hardcoded into test/test_flac.sh */
+	if(!generate_noise("noise.raw", 65536 * 8 * 3)) return 1;
+	if(!generate_noise("noise8m32.raw", 32)) return 1;
+	if(!generate_wackywavs()) return 1;
+	if(!generate_wackywav64s()) return 1;
+	if(!generate_wackyrf64s()) return 1;
+	if(!generate_noisy_sine()) return 1;
+	for(channels = 1; channels <= 8; channels *= 2) {
+		unsigned bits_per_sample;
+		for(bits_per_sample = 8; bits_per_sample <= 24; bits_per_sample += 4) {
+			static const unsigned nsamples[] = { 1, 111, 4777 } ;
+			unsigned samples;
+			for(samples = 0; samples < sizeof(nsamples)/sizeof(nsamples[0]); samples++) {
+				char fn[64];
+
+				flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.aiff", channels, bits_per_sample, nsamples[samples]);
+				if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples]))
+					return 1;
+
+				flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.wav", channels, bits_per_sample, nsamples[samples]);
+				if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/0))
+					return 1;
+
+				flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.rf64", channels, bits_per_sample, nsamples[samples]);
+				if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/1))
+					return 1;
+
+				flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.w64", channels, bits_per_sample, nsamples[samples]);
+				if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/2))
+					return 1;
+
+				if(bits_per_sample % 8 == 0) {
+					flac_snprintf(fn, sizeof (fn), "rt-%u-%u-signed-%u.raw", channels, bits_per_sample, nsamples[samples]);
+					if(!generate_signed_raw(fn, channels, bits_per_sample/8, nsamples[samples]))
+						return 1;
+					flac_snprintf(fn, sizeof (fn), "rt-%u-%u-unsigned-%u.raw", channels, bits_per_sample, nsamples[samples]);
+					if(!generate_unsigned_raw(fn, channels, bits_per_sample/8, nsamples[samples]))
+						return 1;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
diff --git a/src/test_streams/test_streams.vcproj b/src/test_streams/test_streams.vcproj
new file mode 100644
index 0000000..65ed81c
--- /dev/null
+++ b/src/test_streams/test_streams.vcproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="test_streams"

+	ProjectGUID="{4cefbc91-c215-11db-8314-0800200c9a66}"

+	RootNamespace="test_streams"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CompileAs="0"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/test_streams/test_streams.vcxproj b/src/test_streams/test_streams.vcxproj
new file mode 100644
index 0000000..037f9ab
--- /dev/null
+++ b/src/test_streams/test_streams.vcxproj
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc91-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>test_streams</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <CompileAs>Default</CompileAs>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\share\grabbag\grabbag_static.vcxproj">

+      <Project>{4cefbc81-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/test_streams/test_streams.vcxproj.filters b/src/test_streams/test_streams.vcxproj.filters
new file mode 100644
index 0000000..5c9040b
--- /dev/null
+++ b/src/test_streams/test_streams.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
new file mode 100644
index 0000000..7696a6c
--- /dev/null
+++ b/src/utils/Makefile.am
@@ -0,0 +1,19 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = flacdiff flactimer
diff --git a/src/utils/flacdiff/CMakeLists.txt b/src/utils/flacdiff/CMakeLists.txt
new file mode 100644
index 0000000..ec9f771
--- /dev/null
+++ b/src/utils/flacdiff/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(flacdiff
+    main.cpp
+    $<$<BOOL:${WIN32}>:../../../include/share/win_utf8_io.h>
+    $<$<BOOL:${WIN32}>:../../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(flacdiff FLAC++)
diff --git a/src/utils/flacdiff/Makefile.am b/src/utils/flacdiff/Makefile.am
new file mode 100644
index 0000000..65f49d7
--- /dev/null
+++ b/src/utils/flacdiff/Makefile.am
@@ -0,0 +1,25 @@
+#  flacdiff - Displays where two FLAC streams differ
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	flacdiff.vcproj \
+	flacdiff.vcxproj \
+	flacdiff.vcxproj.filters \
+	main.cpp
diff --git a/src/utils/flacdiff/Makefile.lite b/src/utils/flacdiff/Makefile.lite
new file mode 100644
index 0000000..bd15022
--- /dev/null
+++ b/src/utils/flacdiff/Makefile.lite
@@ -0,0 +1,47 @@
+#  flacdiff - Displays where two FLAC streams differ
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../../..
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = flacdiff
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = $(libdir)/libFLAC++.a $(libdir)/libFLAC.a $(OGG_EXPLICIT_LIBS) -lm
+else
+ifeq ($(findstring Windows,$(OS)),Windows)
+    LIBS = -lFLAC++ -lFLAC -lwin_utf8_io $(OGG_LIBS) -lm
+else
+    LIBS = -lFLAC++ -lFLAC $(OGG_LIBS) -lm
+endif
+endif
+
+SRCS_CPP = \
+	main.cpp
+
+include $(topdir)/build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/utils/flacdiff/flacdiff.vcproj b/src/utils/flacdiff/flacdiff.vcproj
new file mode 100644
index 0000000..e7831e2
--- /dev/null
+++ b/src/utils/flacdiff/flacdiff.vcproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="flacdiff"

+	ProjectGUID="{4cefbc93-c215-11db-8314-0800200c9a66}"

+	RootNamespace="flacdiff"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="$(SolutionDir)objs\$(ConfigurationName)\lib\libogg_static.lib"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\main.cpp"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/utils/flacdiff/flacdiff.vcxproj b/src/utils/flacdiff/flacdiff.vcxproj
new file mode 100644
index 0000000..448f269
--- /dev/null
+++ b/src/utils/flacdiff/flacdiff.vcxproj
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc93-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>flacdiff</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(SolutionDir)objs\$(Platform)\$(Configuration)\lib\libogg_static.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\..\libFLAC++\libFLAC++_static.vcxproj">

+      <Project>{4cefbc86-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\..\libFLAC\libFLAC_static.vcxproj">

+      <Project>{4cefbc84-c215-11db-8314-0800200c9a66}</Project>

+    </ProjectReference>

+    <ProjectReference Include="..\..\share\win_utf8_io\win_utf8_io_static.vcxproj">

+      <Project>{4cefbe02-c215-11db-8314-0800200c9a66}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/utils/flacdiff/flacdiff.vcxproj.filters b/src/utils/flacdiff/flacdiff.vcxproj.filters
new file mode 100644
index 0000000..61a7d12
--- /dev/null
+++ b/src/utils/flacdiff/flacdiff.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/utils/flacdiff/main.cpp b/src/utils/flacdiff/main.cpp
new file mode 100644
index 0000000..6a42db1
--- /dev/null
+++ b/src/utils/flacdiff/main.cpp
@@ -0,0 +1,230 @@
+/* flacdiff - Displays where two FLAC streams differ
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "FLAC++/decoder.h"
+#include "share/compat.h"
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+class AutoFILE {
+protected:
+	::FILE *f_;
+public:
+	inline AutoFILE(const char *path, const char *mode): f_(::fopen(path, mode)) { }
+	inline virtual ~AutoFILE() { if (f_) (void)::fclose(f_); }
+
+	inline operator bool() const { return 0 != f_; }
+	inline operator const ::FILE *() const { return f_; }
+	inline operator ::FILE *() { return f_; }
+private:
+	AutoFILE();
+	AutoFILE(const AutoFILE &);
+	void operator=(const AutoFILE &);
+};
+
+class Decoder: public FLAC::Decoder::Stream {
+public:
+	Decoder(AutoFILE &f, FLAC__off_t tgt): tgtpos_((FLAC__uint64)tgt), curpos_(0), go_(true), err_(false), frame_(), f_(f) { memset(&frame_, 0, sizeof(::FLAC__Frame)); }
+	FLAC__uint64 tgtpos_, curpos_;
+	bool go_, err_;
+	::FLAC__Frame frame_;
+protected:
+	AutoFILE &f_;
+	// from FLAC::Decoder::Stream
+	virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)
+	{
+		*bytes = fread(buffer, 1, *bytes, f_);
+		if(ferror((FILE*)f_))
+			return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		else if(*bytes == 0 && feof((FILE*)f_))
+			return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+		else
+			return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+	}
+
+	virtual ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset)
+	{
+		FLAC__off_t off = ftello(f_);
+		if(off < 0)
+			return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+		*absolute_byte_offset = off;
+		return ::FLAC__STREAM_DECODER_TELL_STATUS_OK;
+	}
+
+	virtual bool eof_callback()
+	{
+		return (bool)feof((FILE*)f_);
+	}
+
+	virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const /*buffer*/[])
+	{
+		FLAC__uint64 pos;
+		if(!get_decode_position(&pos)) {
+			go_ = false;
+			err_ = true;
+			return ::FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+		if(pos > tgtpos_) {
+			go_ = false;
+			frame_ = *frame;
+		}
+		else
+			curpos_ = pos;
+		return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+	}
+
+	virtual void error_callback(::FLAC__StreamDecoderErrorStatus status)
+	{
+		fprintf(stderr, "got error %d:%s\n", status, ::FLAC__StreamDecoderErrorStatusString[status]);
+		go_ = false;
+		err_ = true;
+	}
+};
+
+static bool show_diff(AutoFILE &f1, AutoFILE &f2, FLAC__off_t off)
+{
+	Decoder d1(f1, off), d2(f2, off);
+	if(!d1) {
+		fprintf(stderr, "ERROR: setting up decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1));
+		return false;
+	}
+	if(!d2) {
+		fprintf(stderr, "ERROR: setting up decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2));
+		return false;
+	}
+	::FLAC__StreamDecoderInitStatus is;
+	if((is = d1.init()) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		fprintf(stderr, "ERROR: initializing decoder1, status=%s state=%s\n", FLAC__StreamDecoderInitStatusString[is], d1.get_state().resolved_as_cstring(d1));
+		return false;
+	}
+	if((is = d2.init()) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		fprintf(stderr, "ERROR: initializing decoder2, status=%s state=%s\n", FLAC__StreamDecoderInitStatusString[is], d2.get_state().resolved_as_cstring(d2));
+		return false;
+	}
+	if(!d1.process_until_end_of_metadata()) {
+		fprintf(stderr, "ERROR: skipping metadata in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1));
+		return false;
+	}
+	if(!d2.process_until_end_of_metadata()) {
+		fprintf(stderr, "ERROR: skipping metadata in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2));
+		return false;
+	}
+	while(d1.go_ && d2.go_) {
+		if(!d1.process_single()) {
+			fprintf(stderr, "ERROR: decoding frame in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1));
+			return false;
+		}
+		if(!d2.process_single()) {
+			fprintf(stderr, "ERROR: decoding frame in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2));
+			return false;
+		}
+	}
+	if(d1.err_) {
+		fprintf(stderr, "ERROR: got err_ in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1));
+		return false;
+	}
+	if(d2.err_) {
+		fprintf(stderr, "ERROR: got err_ in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2));
+		return false;
+	}
+	if(d1.go_ != d2.go_) {
+		fprintf(stderr, "ERROR: d1.go_(%s) != d2.go_(%s)\n", d1.go_?"true":"false", d2.go_?"true":"false");
+		return false;
+	}
+	fprintf(stdout, "pos1 = %" PRIu64 "  blocksize=%u sample#%" PRIu64 " frame#%" PRIu64 "\n", d1.curpos_, d1.frame_.header.blocksize, d1.frame_.header.number.sample_number, d1.frame_.header.number.sample_number / d1.frame_.header.blocksize);
+	fprintf(stdout, "pos2 = %" PRIu64 "  blocksize=%u sample#%" PRIu64 " frame#%" PRIu64 "\n", d2.curpos_, d2.frame_.header.blocksize, d2.frame_.header.number.sample_number, d2.frame_.header.number.sample_number / d2.frame_.header.blocksize);
+
+	return true;
+}
+
+static FLAC__off_t get_diff_offset(AutoFILE &f1, AutoFILE &f2)
+{
+	FLAC__off_t off = 0;
+	while(1) {
+		if(feof((FILE*)f1) && feof((FILE*)f2)) {
+			fprintf(stderr, "ERROR: files are identical\n");
+			return -1;
+		}
+		if(feof((FILE*)f1)) {
+			fprintf(stderr, "ERROR: file1 EOF\n");
+			return -1;
+		}
+		if(feof((FILE*)f2)) {
+			fprintf(stderr, "ERROR: file2 EOF\n");
+			return -1;
+		}
+		if(fgetc(f1) != fgetc(f2))
+			return off;
+		off++;
+	}
+}
+
+static bool run(const char *fn1, const char *fn2)
+{
+	FLAC__off_t off;
+	AutoFILE f1(fn1, "rb"), f2(fn2, "rb");
+
+	if(!f1) {
+		flac_fprintf(stderr, "ERROR: opening %s for reading\n", fn1);
+		return false;
+	}
+	if(!f2) {
+		flac_fprintf(stderr, "ERROR: opening %s for reading\n", fn2);
+		return false;
+	}
+
+	if((off = get_diff_offset(f1, f2)) < 0)
+		return false;
+
+	fprintf(stdout, "got diff offset = %" PRId64 "\n", off);
+
+	return show_diff(f1, f2, off);
+}
+
+int main(int argc, char *argv[])
+{
+	const char *usage = "usage: flacdiff flacfile1 flacfile2\n";
+
+#ifdef _WIN32
+	if (get_utf8_argv(&argc, &argv) != 0) {
+		fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n");
+		return 1;
+	}
+#endif
+
+	if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+		printf(usage);
+		return 0;
+	}
+	else if(argc != 3) {
+		fprintf(stderr, usage);
+		return 255;
+	}
+
+	return run(argv[1], argv[2])? 0 : 1;
+}
diff --git a/src/utils/flactimer/CMakeLists.txt b/src/utils/flactimer/CMakeLists.txt
new file mode 100644
index 0000000..47bf1e5
--- /dev/null
+++ b/src/utils/flactimer/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(flactimer main.cpp)
+target_link_libraries(flactimer FLAC++)
diff --git a/src/utils/flactimer/Makefile.am b/src/utils/flactimer/Makefile.am
new file mode 100644
index 0000000..cfe209c
--- /dev/null
+++ b/src/utils/flactimer/Makefile.am
@@ -0,0 +1,25 @@
+#  flactimer - Runs a command and prints timing information
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	Makefile.lite \
+	flactimer.vcproj \
+	flactimer.vcxproj \
+	flactimer.vcxproj.filters \
+	main.cpp
diff --git a/src/utils/flactimer/Makefile.lite b/src/utils/flactimer/Makefile.lite
new file mode 100644
index 0000000..b0a9834
--- /dev/null
+++ b/src/utils/flactimer/Makefile.lite
@@ -0,0 +1,43 @@
+#  flactimer - Runs a command and prints timing information
+#  Copyright (C) 2007-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# GNU makefile
+#
+
+topdir = ../../..
+libdir = $(topdir)/objs/$(BUILD)/lib
+
+PROGRAM_NAME = flactimer
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(OS),Darwin)
+    EXPLICIT_LIBS = -lm
+else
+    LIBS = -lm
+endif
+
+SRCS_CPP = \
+	main.cpp
+
+include $(topdir)/build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/utils/flactimer/flactimer.vcproj b/src/utils/flactimer/flactimer.vcproj
new file mode 100644
index 0000000..b18bf60
--- /dev/null
+++ b/src/utils/flactimer/flactimer.vcproj
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="flactimer"

+	ProjectGUID="{4cefbc95-c215-11db-8314-0800200c9a66}"

+	RootNamespace="flactimer"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;..\..\..\include"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="2"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)objs\$(ConfigurationName)\bin"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				EnableIntrinsicFunctions="true"

+				FavorSizeOrSpeed="1"

+				OmitFramePointers="true"

+				WholeProgramOptimization="true"

+				AdditionalIncludeDirectories=".;..\..\..\include"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4267;4996"

+				ForcedIncludeFiles="share/msvc2005_int.h"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="1"

+				IgnoreDefaultLibraryNames="uuid.lib"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				LinkTimeCodeGeneration="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93993580-89BD-4b40-88EB-625FBE52EBFB}"

+			>

+		</Filter>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4CF737F1-C7A5-4367-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\main.cpp"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/utils/flactimer/flactimer.vcxproj b/src/utils/flactimer/flactimer.vcxproj
new file mode 100644
index 0000000..9dd8322
--- /dev/null
+++ b/src/utils/flactimer/flactimer.vcxproj
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{4cefbc95-c215-11db-8314-0800200c9a66}</ProjectGuid>

+    <RootNamespace>flactimer</RootNamespace>

+    <Keyword>Win32Proj</Keyword>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)objs\$(Configuration)\bin\</OutDir>

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+    <OutDir>$(SolutionDir)objs\$(Platform)\$(Configuration)\bin\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MinimalRebuild>true</MinimalRebuild>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+      <TargetMachine>MachineX86</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>

+      <OmitFramePointers>true</OmitFramePointers>

+      <WholeProgramOptimization>true</WholeProgramOptimization>

+      <AdditionalIncludeDirectories>.;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

+      <BufferSecurityCheck>false</BufferSecurityCheck>

+      <WarningLevel>Level3</WarningLevel>

+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

+      <DisableSpecificWarnings>4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+    </ClCompile>

+    <Link>

+      <IgnoreSpecificDefaultLibraries>uuid.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <SubSystem>Console</SubSystem>

+      <OptimizeReferences>true</OptimizeReferences>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="main.cpp" />

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/utils/flactimer/flactimer.vcxproj.filters b/src/utils/flactimer/flactimer.vcxproj.filters
new file mode 100644
index 0000000..bc32d54
--- /dev/null
+++ b/src/utils/flactimer/flactimer.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93993580-89BD-4b40-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4CF737F1-C7A5-4367-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="main.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/utils/flactimer/main.cpp b/src/utils/flactimer/main.cpp
new file mode 100644
index 0000000..62f00e4
--- /dev/null
+++ b/src/utils/flactimer/main.cpp
@@ -0,0 +1,175 @@
+/* flactimer - Runs a command and prints timing information
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+#include "share/compat.h"
+#include "share/safe_str.h"
+
+static inline uint64_t time2nsec(const FILETIME &t)
+{
+	uint64_t n = t.dwHighDateTime;
+	n <<= 32;
+	n |= (uint64_t)t.dwLowDateTime;
+	return n * 100;
+}
+
+static void printtime(FILE *fout, uint64_t nsec, uint64_t total)
+{
+	uint32_t pct = (uint32_t)(100.0 * ((double)nsec / (double)total));
+	uint64_t msec = nsec / 1000000; nsec -= msec * 1000000;
+	uint64_t sec = msec / 1000; msec -= sec * 1000;
+	uint64_t min = sec / 60; sec -= min * 60;
+	uint64_t hour = min / 60; min -= hour * 60;
+	fprintf(fout, " %5u.%03u = %02u:%02u:%02u.%03u = %3u%%\n",
+		(uint32_t)((hour*60+min)*60+sec),
+		(uint32_t)msec,
+		(uint32_t)hour,
+		(uint32_t)min,
+		(uint32_t)sec,
+		(uint32_t)msec,
+		pct
+	);
+}
+
+int main(int argc, char *argv[])
+{
+	const char *usage = "usage: flactimer [-1 | -2 | -o outputfile] command\n";
+	FILE *fout = stderr;
+
+	if(argc == 1 || (argc > 1 && 0 == strcmp(argv[1], "-h"))) {
+		fprintf(stderr, usage);
+		return 0;
+	}
+	argv++;
+	argc--;
+	if(0 == strcmp(argv[0], "-1") || 0 == strcmp(argv[0], "/1")) {
+		fout = stdout;
+		argv++;
+		argc--;
+	}
+	else if(0 == strcmp(argv[0], "-2") || 0 == strcmp(argv[0], "/2")) {
+		fout = stdout;
+		argv++;
+		argc--;
+	}
+	else if(0 == strcmp(argv[0], "-o")) {
+		if(argc < 2) {
+			fprintf(stderr, usage);
+			return 1;
+		}
+		fout = fopen(argv[1], "w");
+		if(!fout) {
+			fprintf(stderr, "ERROR opening file %s for writing\n", argv[1]);
+			return 1;
+		}
+		argv += 2;
+		argc -= 2;
+	}
+	if(argc <= 0) {
+		fprintf(fout, "ERROR, no command!\n\n");
+		fprintf(fout, usage);
+		fclose(fout);
+		return 1;
+	}
+
+	// improvement: double-quote all args
+	int i, n = 0;
+	for(i = 0; i < argc; i++) {
+		if(i > 0)
+			n++;
+		n += strlen(argv[i]);
+	}
+	char *args = (char*)malloc(n+1);
+	if(!args) {
+		fprintf(fout, "ERROR, no memory\n");
+		fclose(fout);
+		return 1;
+	}
+	args[0] = '\0';
+	for(i = 0; i < argc; i++) {
+		if(i > 0)
+			safe_strncat(args, " ", sizeof(args));
+		safe_strncat(args, argv[i], sizeof(args));
+	}
+
+	//fprintf(stderr, "@@@ cmd=[%s] args=[%s]\n", argv[0], args);
+
+	STARTUPINFOA si;
+	GetStartupInfoA(&si);
+
+	DWORD wallclock_msec = GetTickCount();
+
+	PROCESS_INFORMATION pi;
+	BOOL ok = CreateProcessA(
+		argv[0], // lpApplicationName
+		args, // lpCommandLine
+		NULL, // lpProcessAttributes
+		NULL, // lpThreadAttributes
+		FALSE, // bInheritHandles
+		0, // dwCreationFlags
+		NULL, // lpEnvironment
+		NULL, // lpCurrentDirectory
+		&si, // lpStartupInfo (inherit from this proc?)
+		&pi // lpProcessInformation
+	);
+
+	if(!ok) {
+		fprintf(fout, "ERROR running command\n");
+		free(args); //@@@ ok to free here or have to wait to wait till process is reaped?
+		fclose(fout);
+		return 1;
+	}
+
+	//fprintf(stderr, "@@@ waiting...\n");
+	WaitForSingleObject(pi.hProcess, INFINITE);
+	//fprintf(stderr, "@@@ done\n");
+
+	wallclock_msec = GetTickCount() - wallclock_msec;
+
+	FILETIME creation_time;
+	FILETIME exit_time;
+	FILETIME kernel_time;
+	FILETIME user_time;
+	if(!GetProcessTimes(pi.hProcess, &creation_time, &exit_time, &kernel_time, &user_time)) {
+		fprintf(fout, "ERROR getting time info\n");
+		free(args); //@@@ ok to free here or have to wait to wait till process is reaped?
+		fclose(fout);
+		return 1;
+	}
+	uint64_t kernel_nsec = time2nsec(kernel_time);
+	uint64_t user_nsec = time2nsec(user_time);
+
+	fprintf(fout, "Kernel Time  = "); printtime(fout, kernel_nsec, (uint64_t)wallclock_msec * 1000000);
+	fprintf(fout, "User Time    = "); printtime(fout, user_nsec, (uint64_t)wallclock_msec * 1000000);
+	fprintf(fout, "Process Time = "); printtime(fout, kernel_nsec+user_nsec, (uint64_t)wallclock_msec * 1000000);
+	fprintf(fout, "Global Time  = "); printtime(fout, (uint64_t)wallclock_msec * 1000000, (uint64_t)wallclock_msec * 1000000);
+
+	CloseHandle(pi.hThread);
+	CloseHandle(pi.hProcess);
+
+	free(args); //@@@ always causes crash, maybe CreateProcess takes ownership?
+	fclose(fout);
+	return 0;
+}
diff --git a/src/utils/loudness/loudness.sci b/src/utils/loudness/loudness.sci
new file mode 100644
index 0000000..a476a17
--- /dev/null
+++ b/src/utils/loudness/loudness.sci
@@ -0,0 +1,115 @@
+// Equal Loudness Filter
+//
+// Adapted from original MATLAB code written by David Robinson
+//
+//      http://replaygain.hydrogenaudio.org/proposal/equal_loudness.html
+//      http://replaygain.hydrogenaudio.org/proposal/mfiles/equalloudfilt.m
+
+// *****************************************************************************
+// Print Filter Coefficients
+//
+// This function takes a vector of filter tap settings, and prints
+// each tap setting from least significant to most significant.
+
+function c=printcoeff(p)
+
+  c=coeff(p);
+  c=c($:-1:1);
+
+  for ix = 1:1:length(c)
+    if ix > 1
+        printf(" ")
+    end
+    printf("%.14f", c(ix));
+  end
+
+endfunction
+
+// *****************************************************************************
+// Equal Loudness Filter
+//
+// This function is adapted from David Robison's original MATLAB code.
+// Apart from changes to port it to scilab, the other change is to
+// use a single specification of the frequency points in the 80dB Equal
+// Loudness curve.
+//
+// The original code had different curves for different sampling
+// frequencies. This code dynamically computes the current data
+// points to use as determined by the Nyquist frequency.
+
+function [a1,b1,a2,b2]=equalloudfilt(fs);
+// Design a filter to match equal loudness curves
+// 9/7/2001
+
+[%nargout,%nargin]=argn(0);
+
+// If the user hasn't specified a sampling frequency, use the CD default
+if %nargin<1 then
+   fs=44100;
+end
+
+// Specify the 80 dB Equal Loudness curve
+EL80=[0,120;20,113;30,103;40,97;50,93;60,91;70,89;80,87;90,86; ..
+      ..
+      100,85;200,78;300,76;400,76;500,76;600,76;700,77;800,78;900,79.5; ..
+      ..
+      1000,80;1500,79;2000,77;2500,74;3000,71.5;3700,70;4000,70.5; ..
+      5000,74;6000,79;7000,84;8000,86;9000,86; ..
+      ..
+      10000,85;12000,95;15000,110;20000,125;24000,140];
+
+for ex = 1:1:length(EL80(:,1))
+  if EL80(ex,1) > fs/2
+    EL80 = [ EL80(1:ex-1,:); fs/2, EL80(ex-1,2) ];
+    break
+  elseif EL80(ex,1) == fs/2
+    EL80 = EL80(1:ex,:);
+    break
+  end
+  if ex == length(EL80(:,1))
+    EL80 = [ EL80(1:$, :); fs/2, EL80($,2) ];
+  end
+end
+
+// convert frequency and amplitude of the equal loudness curve into format suitable for yulewalk
+f=EL80(:,1)./(fs/2);
+m=10.^((70-EL80(:,2))/20);
+
+// Use a MATLAB utility to design a best bit IIR filter
+[b1,a1]=yulewalk(10,f,m);
+
+// Add a 2nd order high pass filter at 150Hz to finish the job
+hz=iir(2,'hp','butt',[150/fs,0],[1e-3 1e-3]);
+b2=numer(hz); // b2=b2($:-1:1);
+a2=denom(hz); // a2=a2($:-1:1);
+
+endfunction
+
+// *****************************************************************************
+// Generate Filter Taps
+//
+// Generate the filter taps for each of the desired frequencies.
+
+format('v', 16);
+
+freqs = [  8000 11025 12000 16000 18900 22050 24000 ..
+          28000 32000 36000 37800 44100 48000 ];
+
+for fx = 1:1:length(freqs)
+
+  printf("\n%d\n", freqs(fx));
+
+  [a1,b1,a2,b2] = equalloudfilt(freqs(fx));
+
+  printf("{ "); bb=printcoeff(b1); printf(" }\n");
+  printf("{ "); aa=printcoeff(a1); printf(" }\n");
+
+  printf("{ "); printcoeff(b2); printf(" }\n");
+  printf("{ "); printcoeff(a2); printf(" }\n");
+
+// freqz_fwd(bb,aa,1024,freqs(fx));
+
+end
+
+
+quit
diff --git a/strip_non_asm_libtool_args.sh b/strip_non_asm_libtool_args.sh
new file mode 100755
index 0000000..d5a61f1
--- /dev/null
+++ b/strip_non_asm_libtool_args.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# libtool assumes that the compiler can handle the -fPIC flag.
+# This isn't always true (for example, nasm can't handle it).
+# Also, on some versions of OS X it tries to pass -fno-common
+# to 'as' which causes problems.
+command=""
+while [ $1 ]; do
+	if [ "$1" != "-fPIC" ]; then
+		if [ "$1" != "-DPIC" ]; then
+			if [ "$1" != "-fno-common" ]; then
+				command="$command $1"
+			fi
+		fi
+	fi
+	shift
+done
+echo $command
+exec $command
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..238144c
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,49 @@
+if(NOT UNIX)
+    return()
+endif()
+
+if(WIN32)
+    set(EXEEXT .exe)
+endif()
+set(top_srcdir "${PROJECT_SOURCE_DIR}")
+set(top_builddir "${PROJECT_BINARY_DIR}")
+configure_file(common.sh.in common.sh @ONLY)
+
+set(ALL_TESTS libFLAC grabbag flac metaflac replaygain seeking streams compression)
+
+add_test(NAME libFLAC
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_libFLAC.sh"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+if(BUILD_CXXLIBS)
+    add_test(NAME libFLAC++
+        COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_libFLAC++.sh"
+        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+    list(APPEND ALL_TESTS libFLAC++)
+endif()
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cuesheets")
+add_test(NAME grabbag
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_grabbag.sh"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+add_test(NAME flac
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_flac.sh"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/metaflac-test-files")
+add_test(NAME metaflac
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_metaflac.sh"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+add_test(NAME replaygain
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_replaygain.sh"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+add_test(NAME seeking
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_seeking.sh"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+add_test(NAME streams
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_streams.sh"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+#   increase this if standard 1500 seconds are not enough
+#   set_tests_properties(streams PROPERTIES TIMEOUT 1500)
+add_test(NAME compression
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_compression.sh"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+
+set_property(TEST ${ALL_TESTS} APPEND PROPERTY ENVIRONMENT ECHO_C=\\c)
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..dcd911d
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,62 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+TESTS_ENVIRONMENT = FLAC__TEST_LEVEL=@FLAC__TEST_LEVEL@ FLAC__TEST_WITH_VALGRIND=@FLAC__TEST_WITH_VALGRIND@ ECHO_N="@ECHO_N@" ECHO_C="@ECHO_C@"
+
+SUBDIRS = cuesheets flac-to-flac-metadata-test-files metaflac-test-files pictures
+
+check_SCRIPTS = \
+	test_libFLAC.sh \
+	test_libFLAC++.sh \
+	test_grabbag.sh \
+	test_flac.sh \
+	test_metaflac.sh \
+	test_replaygain.sh \
+	test_seeking.sh \
+	test_streams.sh \
+	test_compression.sh
+
+# This one should pass when building out-of-tree (e.g. 'make distcheck').
+check: $(check_SCRIPTS)
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_libFLAC.sh
+if FLaC__WITH_CPPLIBS
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_libFLAC++.sh
+endif
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_grabbag.sh
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_flac.sh
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_metaflac.sh
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_replaygain.sh
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_seeking.sh
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_streams.sh
+	$(TESTS_ENVIRONMENT) $(srcdir)/test_compression.sh
+	@echo "----------------"
+	@echo "All tests passed"
+	@echo "----------------"
+
+EXTRA_DIST = \
+    CMakeLists.txt \
+	Makefile.lite \
+	cuesheet.ok \
+	metaflac.flac.in \
+	metaflac.flac.ok \
+	picture.ok \
+	$(check_SCRIPTS) \
+	write_iff.pl
+
+clean-local:
+	-rm -f *.raw *.flac *.oga *.ogg *.cmp *.aiff *.wav *.w64 *.rf64 *.diff *.log *.cue core
diff --git a/test/Makefile.lite b/test/Makefile.lite
new file mode 100644
index 0000000..0bec1a1
--- /dev/null
+++ b/test/Makefile.lite
@@ -0,0 +1,56 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU makefile
+#
+
+topdir = ..
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+all: clean
+	sed 's|@top_srcdir@|$(topdir)|;s|@EXEEXT@| |' common.sh.in > common.sh
+	$(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_libFLAC.sh $(CONFIG)
+	$(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_libFLAC++.sh $(CONFIG)
+	$(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_grabbag.sh $(CONFIG)
+	$(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_flac.sh $(CONFIG)
+	$(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_metaflac.sh $(CONFIG)
+	$(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_seeking.sh $(CONFIG)
+	$(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_streams.sh $(CONFIG)
+
+debug   : FLAC__TEST_LEVEL=FLAC__TEST_LEVEL=2
+valgrind: FLAC__TEST_LEVEL=FLAC__TEST_LEVEL=1
+release : FLAC__TEST_LEVEL=FLAC__TEST_LEVEL=2
+
+debug   : FLAC__TEST_WITH_VALGRIND=FLAC__TEST_WITH_VALGRIND=no
+valgrind: FLAC__TEST_WITH_VALGRIND=FLAC__TEST_WITH_VALGRIND=yes
+release : FLAC__TEST_WITH_VALGRIND=FLAC__TEST_WITH_VALGRIND=no
+
+debug   : CONFIG = debug
+valgrind: CONFIG = debug
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+clean:
+	rm -f *.raw *.flac *.oga *.ogg *.cmp *.aiff *.wav *.w64 *.rf64 *.diff *.log *.cue core flac-to-flac-metadata-test-files/out.* metaflac-test-files/out.*
diff --git a/test/common.sh.in b/test/common.sh.in
new file mode 100644
index 0000000..0884bbc
--- /dev/null
+++ b/test/common.sh.in
@@ -0,0 +1,83 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+export MALLOC_CHECK_=3
+export MALLOC_PERTURB_=$((RANDOM % 255 + 1))
+
+if [ x = x"$1" ] ; then
+	BUILD=debug
+else
+	BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../objs/$BUILD/lib:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../objs/$BUILD/lib:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/getopt/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/replaygain_synthesis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/utf8/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/libFLAC++/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/getopt/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_synthesis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/utf8/.libs:$LD_LIBRARY_PATH
+
+export LD_LIBRARY_PATH
+
+EXE=@EXEEXT@
+
+# Needed for building out-of-tree where source files are in the $top_srcdir tree
+# and build products in the $top_builddir tree.
+top_srcdir=@top_srcdir@
+top_builddir=@top_builddir@
+
+# Set `is_win` variable which is used in other scripts that source this one.
+if test $(env | grep -ic '^comspec=') != 0 ; then
+	is_win=yes
+else
+	is_win=no
+fi
+
+# change to 'false' to show all flac/metaflac output (useful for debugging)
+if true ; then
+	SILENT='--silent'
+	TOTALLY_SILENT='--totally-silent'
+else
+	SILENT=''
+	TOTALLY_SILENT=''
+fi
+
+# Functions
+
+die ()
+{
+	echo $* 1>&2
+	exit 1
+}
+
+make_streams ()
+{
+	echo "Generating streams..."
+	if [ ! -f wacky1.wav ] ; then
+		test_streams${EXE} || die "ERROR during test_streams"
+	fi
+}
diff --git a/test/cuesheet.ok b/test/cuesheet.ok
new file mode 100644
index 0000000..dc9c82f
--- /dev/null
+++ b/test/cuesheet.ok
@@ -0,0 +1,94 @@
+NEGATIVE cuesheets/bad.000.CATALOG_multiple.cue
+pass1: parse error, line 2: "found multiple CATALOG commands"
+NEGATIVE cuesheets/bad.001.CATALOG_missing_number.cue
+pass1: parse error, line 1: "CATALOG is missing catalog number"
+NEGATIVE cuesheets/bad.002.CATALOG_number_too_long.cue
+pass1: parse error, line 1: "CATALOG number is too long"
+NEGATIVE cuesheets/bad.003.CATALOG_not_13_digits.cue
+pass1: parse error, line 1: "CD-DA CATALOG number must be 13 decimal digits"
+NEGATIVE cuesheets/bad.030.FLAGS_multiple.cue
+pass1: parse error, line 4: "found multiple FLAGS commands"
+NEGATIVE cuesheets/bad.031.FLAGS_wrong_place_1.cue
+pass1: parse error, line 1: "FLAGS command must come after TRACK but before INDEX"
+NEGATIVE cuesheets/bad.032.FLAGS_wrong_place_2.cue
+pass1: parse error, line 4: "FLAGS command must come after TRACK but before INDEX"
+NEGATIVE cuesheets/bad.060.INDEX_wrong_place.cue
+pass1: parse error, line 2: "found INDEX before any TRACK"
+NEGATIVE cuesheets/bad.061.INDEX_missing_number.cue
+pass1: parse error, line 4: "INDEX is missing index number"
+NEGATIVE cuesheets/bad.062.INDEX_invalid_number_1.cue
+pass1: parse error, line 4: "INDEX has invalid index number"
+NEGATIVE cuesheets/bad.063.first_INDEX_not_0_or_1.cue
+pass1: parse error, line 4: "first INDEX number of a TRACK must be 0 or 1"
+NEGATIVE cuesheets/bad.064.INDEX_num_non_sequential.cue
+pass1: parse error, line 5: "INDEX numbers must be sequential"
+NEGATIVE cuesheets/bad.065.INDEX_num_out_of_range.cue
+pass1: parse error, line 104: "CD-DA INDEX number must be between 0 and 99, inclusive"
+NEGATIVE cuesheets/bad.066.INDEX_missing_offset.cue
+pass1: parse error, line 4: "INDEX is missing an offset after the index number"
+NEGATIVE cuesheets/bad.067.INDEX_illegal_offset.cue
+pass1: parse error, line 4: "illegal INDEX offset (not of the form MM:SS:FF)"
+NEGATIVE cuesheets/bad.068.INDEX_cdda_illegal_offset.cue
+pass1: parse error, line 4: "illegal INDEX offset (not of the form MM:SS:FF)"
+NEGATIVE cuesheets/bad.069.nonzero_first_INDEX.cue
+pass1: parse error, line 4: "first INDEX of first TRACK must have an offset of 00:00:00"
+NEGATIVE cuesheets/bad.070.INDEX_offset_not_ascending_1.cue
+pass1: parse error, line 5: "CD-DA INDEX offsets must increase in time"
+NEGATIVE cuesheets/bad.071.INDEX_offset_not_ascending_2.cue
+pass1: parse error, line 6: "CD-DA INDEX offsets must increase in time"
+NEGATIVE cuesheets/bad.110.ISRC_multiple.cue
+pass1: parse error, line 4: "found multiple ISRC commands"
+NEGATIVE cuesheets/bad.111.ISRC_wrong_place_1.cue
+pass1: parse error, line 2: "ISRC command must come after TRACK but before INDEX"
+NEGATIVE cuesheets/bad.112.ISRC_wrong_place_2.cue
+pass1: parse error, line 4: "ISRC command must come after TRACK but before INDEX"
+NEGATIVE cuesheets/bad.113.ISRC_missing_number.cue
+pass1: parse error, line 3: "ISRC is missing ISRC number"
+NEGATIVE cuesheets/bad.114.ISRC_invalid_number.cue
+pass1: parse error, line 3: "invalid ISRC number"
+NEGATIVE cuesheets/bad.130.TRACK_missing_INDEX_01_1.cue
+pass1: parse error, line 2: "previous TRACK must specify at least one INDEX 01"
+NEGATIVE cuesheets/bad.131.TRACK_missing_INDEX_01_2.cue
+pass1: parse error, line 3: "previous TRACK must specify at least one INDEX 01"
+NEGATIVE cuesheets/bad.132.TRACK_missing_INDEX_01_3.cue
+pass1: parse error, line 3: "previous TRACK must specify at least one INDEX 01"
+NEGATIVE cuesheets/bad.133.TRACK_missing_INDEX_01_4.cue
+pass1: parse error, line 4: "previous TRACK must specify at least one INDEX 01"
+NEGATIVE cuesheets/bad.134.TRACK_missing_number.cue
+pass1: parse error, line 2: "TRACK is missing track number"
+NEGATIVE cuesheets/bad.135.TRACK_invalid_number_1.cue
+pass1: parse error, line 2: "TRACK has invalid track number"
+NEGATIVE cuesheets/bad.136.TRACK_invalid_number_2.cue
+pass1: parse error, line 2: "TRACK number must be greater than 0"
+NEGATIVE cuesheets/bad.137.TRACK_cdda_out_of_range.cue
+pass1: parse error, line 2: "CD-DA TRACK number must be between 1 and 99, inclusive"
+NEGATIVE cuesheets/bad.138.TRACK_num_non_sequential.cue
+pass1: parse error, line 6: "CD-DA TRACK numbers must be sequential"
+NEGATIVE cuesheets/bad.139.TRACK_missing_type.cue
+pass1: parse error, line 2: "TRACK is missing a track type after the track number"
+NEGATIVE cuesheets/bad.140.no_TRACKs.cue
+pass1: parse error, line 1: "there must be at least one TRACK command"
+NEGATIVE cuesheets/bad.200.FLAC_leadin_missing_offset.cue
+pass1: parse error, line 1: "FLAC__lead-in is missing offset"
+NEGATIVE cuesheets/bad.201.FLAC_leadin_illegal_offset.cue
+pass1: parse error, line 1: "illegal FLAC__lead-in offset"
+NEGATIVE cuesheets/bad.202.FLAC_leadin_cdda_illegal_offset.cue
+pass1: parse error, line 1: "illegal CD-DA FLAC__lead-in offset, must be even multiple of 588 samples"
+NEGATIVE cuesheets/bad.230.FLAC_leadout_multiple.cue
+pass1: parse error, line 3: "multiple FLAC__lead-out commands"
+NEGATIVE cuesheets/bad.231.FLAC_leadout_missing_track.cue
+pass1: parse error, line 1: "FLAC__lead-out is missing track number"
+NEGATIVE cuesheets/bad.232.FLAC_leadout_illegal_track.cue
+pass1: parse error, line 1: "illegal FLAC__lead-out track number"
+NEGATIVE cuesheets/bad.233.FLAC_leadout_missing_offset.cue
+pass1: parse error, line 1: "FLAC__lead-out is missing offset"
+NEGATIVE cuesheets/bad.234.FLAC_leadout_illegal_offset.cue
+pass1: parse error, line 1: "illegal FLAC__lead-out offset"
+NEGATIVE cuesheets/bad.235.FLAC_leadout_offset_not_211680000.cue
+pass1: parse error, line 1: "FLAC__lead-out offset does not match end-of-stream offset"
+POSITIVE cuesheets/good.000.cue
+POSITIVE cuesheets/good.001.cue
+POSITIVE cuesheets/good.002.dos_format.cue
+POSITIVE cuesheets/good.003.missing_final_newline.cue
+POSITIVE cuesheets/good.004.dos_format.missing_final_newline.cue
+POSITIVE cuesheets/good.005.quoted.isrc.cue
diff --git a/test/cuesheets/Makefile.am b/test/cuesheets/Makefile.am
new file mode 100644
index 0000000..eb49171
--- /dev/null
+++ b/test/cuesheets/Makefile.am
@@ -0,0 +1,69 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+	bad.000.CATALOG_multiple.cue \
+	bad.001.CATALOG_missing_number.cue \
+	bad.002.CATALOG_number_too_long.cue \
+	bad.003.CATALOG_not_13_digits.cue \
+	bad.030.FLAGS_multiple.cue \
+	bad.031.FLAGS_wrong_place_1.cue \
+	bad.032.FLAGS_wrong_place_2.cue \
+	bad.060.INDEX_wrong_place.cue \
+	bad.061.INDEX_missing_number.cue \
+	bad.062.INDEX_invalid_number_1.cue \
+	bad.063.first_INDEX_not_0_or_1.cue \
+	bad.064.INDEX_num_non_sequential.cue \
+	bad.065.INDEX_num_out_of_range.cue \
+	bad.066.INDEX_missing_offset.cue \
+	bad.067.INDEX_illegal_offset.cue \
+	bad.068.INDEX_cdda_illegal_offset.cue \
+	bad.069.nonzero_first_INDEX.cue \
+	bad.070.INDEX_offset_not_ascending_1.cue \
+	bad.071.INDEX_offset_not_ascending_2.cue \
+	bad.110.ISRC_multiple.cue \
+	bad.111.ISRC_wrong_place_1.cue \
+	bad.112.ISRC_wrong_place_2.cue \
+	bad.113.ISRC_missing_number.cue \
+	bad.114.ISRC_invalid_number.cue \
+	bad.130.TRACK_missing_INDEX_01_1.cue \
+	bad.131.TRACK_missing_INDEX_01_2.cue \
+	bad.132.TRACK_missing_INDEX_01_3.cue \
+	bad.133.TRACK_missing_INDEX_01_4.cue \
+	bad.134.TRACK_missing_number.cue \
+	bad.135.TRACK_invalid_number_1.cue \
+	bad.136.TRACK_invalid_number_2.cue \
+	bad.137.TRACK_cdda_out_of_range.cue \
+	bad.138.TRACK_num_non_sequential.cue \
+	bad.139.TRACK_missing_type.cue \
+	bad.140.no_TRACKs.cue \
+	bad.200.FLAC_leadin_missing_offset.cue \
+	bad.201.FLAC_leadin_illegal_offset.cue \
+	bad.202.FLAC_leadin_cdda_illegal_offset.cue \
+	bad.230.FLAC_leadout_multiple.cue \
+	bad.231.FLAC_leadout_missing_track.cue \
+	bad.232.FLAC_leadout_illegal_track.cue \
+	bad.233.FLAC_leadout_missing_offset.cue \
+	bad.234.FLAC_leadout_illegal_offset.cue \
+	bad.235.FLAC_leadout_offset_not_211680000.cue \
+	good.000.cue \
+	good.001.cue \
+	good.002.dos_format.cue \
+	good.003.missing_final_newline.cue \
+	good.004.dos_format.missing_final_newline.cue \
+	good.005.quoted.isrc.cue
diff --git a/test/cuesheets/bad.000.CATALOG_multiple.cue b/test/cuesheets/bad.000.CATALOG_multiple.cue
new file mode 100644
index 0000000..ef2769b
--- /dev/null
+++ b/test/cuesheets/bad.000.CATALOG_multiple.cue
@@ -0,0 +1,5 @@
+CATALOG 1234567890123
+CATALOG 0234567890123
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.001.CATALOG_missing_number.cue b/test/cuesheets/bad.001.CATALOG_missing_number.cue
new file mode 100644
index 0000000..ce2334f
--- /dev/null
+++ b/test/cuesheets/bad.001.CATALOG_missing_number.cue
@@ -0,0 +1,4 @@
+CATALOG 
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.002.CATALOG_number_too_long.cue b/test/cuesheets/bad.002.CATALOG_number_too_long.cue
new file mode 100644
index 0000000..8585a0a
--- /dev/null
+++ b/test/cuesheets/bad.002.CATALOG_number_too_long.cue
@@ -0,0 +1,4 @@
+CATALOG 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.003.CATALOG_not_13_digits.cue b/test/cuesheets/bad.003.CATALOG_not_13_digits.cue
new file mode 100644
index 0000000..c75d4c0
--- /dev/null
+++ b/test/cuesheets/bad.003.CATALOG_not_13_digits.cue
@@ -0,0 +1,4 @@
+CATALOG 123456789012z
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.030.FLAGS_multiple.cue b/test/cuesheets/bad.030.FLAGS_multiple.cue
new file mode 100644
index 0000000..ee82b13
--- /dev/null
+++ b/test/cuesheets/bad.030.FLAGS_multiple.cue
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    FLAGS 4CH
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.031.FLAGS_wrong_place_1.cue b/test/cuesheets/bad.031.FLAGS_wrong_place_1.cue
new file mode 100644
index 0000000..3b7f018
--- /dev/null
+++ b/test/cuesheets/bad.031.FLAGS_wrong_place_1.cue
@@ -0,0 +1,4 @@
+FLAGS PRE
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.032.FLAGS_wrong_place_2.cue b/test/cuesheets/bad.032.FLAGS_wrong_place_2.cue
new file mode 100644
index 0000000..926cc91
--- /dev/null
+++ b/test/cuesheets/bad.032.FLAGS_wrong_place_2.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+    FLAGS PRE
diff --git a/test/cuesheets/bad.060.INDEX_wrong_place.cue b/test/cuesheets/bad.060.INDEX_wrong_place.cue
new file mode 100644
index 0000000..fb175f2
--- /dev/null
+++ b/test/cuesheets/bad.060.INDEX_wrong_place.cue
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+INDEX 00 00:00:00
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.061.INDEX_missing_number.cue b/test/cuesheets/bad.061.INDEX_missing_number.cue
new file mode 100644
index 0000000..bf72604
--- /dev/null
+++ b/test/cuesheets/bad.061.INDEX_missing_number.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 
diff --git a/test/cuesheets/bad.062.INDEX_invalid_number_1.cue b/test/cuesheets/bad.062.INDEX_invalid_number_1.cue
new file mode 100644
index 0000000..fcb4dd3
--- /dev/null
+++ b/test/cuesheets/bad.062.INDEX_invalid_number_1.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX thhpt!
diff --git a/test/cuesheets/bad.063.first_INDEX_not_0_or_1.cue b/test/cuesheets/bad.063.first_INDEX_not_0_or_1.cue
new file mode 100644
index 0000000..a136f3f
--- /dev/null
+++ b/test/cuesheets/bad.063.first_INDEX_not_0_or_1.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 02 00:00:00
diff --git a/test/cuesheets/bad.064.INDEX_num_non_sequential.cue b/test/cuesheets/bad.064.INDEX_num_non_sequential.cue
new file mode 100644
index 0000000..9df3b47
--- /dev/null
+++ b/test/cuesheets/bad.064.INDEX_num_non_sequential.cue
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:00:00
+    INDEX 00 00:00:00
diff --git a/test/cuesheets/bad.065.INDEX_num_out_of_range.cue b/test/cuesheets/bad.065.INDEX_num_out_of_range.cue
new file mode 100644
index 0000000..a72d7e0
--- /dev/null
+++ b/test/cuesheets/bad.065.INDEX_num_out_of_range.cue
@@ -0,0 +1,104 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 00 00:00:00
+    INDEX 01 02:10:15
+    INDEX 02 02:20:15
+    INDEX 03 02:30:15
+    INDEX 04 03:30:15
+    INDEX 05 03:31:15
+    INDEX 06 03:32:06
+    INDEX 07 03:32:07
+    INDEX 08 03:32:08
+    INDEX 09 03:32:09
+    INDEX 10 03:32:10
+    INDEX 11 03:32:11
+    INDEX 12 03:32:12
+    INDEX 13 03:32:13
+    INDEX 14 03:32:14
+    INDEX 15 03:32:15
+    INDEX 16 03:32:16
+    INDEX 17 03:32:17
+    INDEX 18 03:32:18
+    INDEX 19 03:32:19
+    INDEX 20 03:32:20
+    INDEX 21 03:32:21
+    INDEX 22 03:32:22
+    INDEX 23 03:32:23
+    INDEX 24 03:32:24
+    INDEX 25 03:32:25
+    INDEX 26 03:32:26
+    INDEX 27 03:32:27
+    INDEX 28 03:32:28
+    INDEX 29 03:32:29
+    INDEX 30 03:32:30
+    INDEX 31 03:32:31
+    INDEX 32 03:32:32
+    INDEX 33 03:32:33
+    INDEX 34 03:32:34
+    INDEX 35 03:32:35
+    INDEX 36 03:32:36
+    INDEX 37 03:32:37
+    INDEX 38 03:32:38
+    INDEX 39 03:32:39
+    INDEX 40 03:32:40
+    INDEX 41 03:32:41
+    INDEX 42 03:32:42
+    INDEX 43 03:32:43
+    INDEX 44 03:32:44
+    INDEX 45 03:32:45
+    INDEX 46 03:32:46
+    INDEX 47 03:32:47
+    INDEX 48 03:32:48
+    INDEX 49 03:32:49
+    INDEX 50 03:32:50
+    INDEX 51 03:32:51
+    INDEX 52 03:32:52
+    INDEX 53 03:32:53
+    INDEX 54 03:32:54
+    INDEX 55 03:32:55
+    INDEX 56 03:32:56
+    INDEX 57 03:32:57
+    INDEX 58 03:32:58
+    INDEX 59 03:32:59
+    INDEX 60 03:32:60
+    INDEX 61 03:32:61
+    INDEX 62 03:32:62
+    INDEX 63 03:32:63
+    INDEX 64 03:32:64
+    INDEX 65 03:32:65
+    INDEX 66 03:32:66
+    INDEX 67 03:32:67
+    INDEX 68 03:32:68
+    INDEX 69 03:32:69
+    INDEX 70 03:40:50
+    INDEX 71 03:40:51
+    INDEX 72 03:40:52
+    INDEX 73 03:40:53
+    INDEX 74 03:40:54
+    INDEX 75 03:40:55
+    INDEX 76 03:40:56
+    INDEX 77 03:40:57
+    INDEX 78 03:40:58
+    INDEX 79 03:40:59
+    INDEX 80 03:41:50
+    INDEX 81 03:41:51
+    INDEX 82 03:41:52
+    INDEX 83 03:41:53
+    INDEX 84 03:41:54
+    INDEX 85 03:41:55
+    INDEX 86 03:41:56
+    INDEX 87 03:41:57
+    INDEX 88 03:41:58
+    INDEX 89 03:41:59
+    INDEX 90 03:42:50
+    INDEX 91 03:42:51
+    INDEX 92 03:42:52
+    INDEX 93 03:42:53
+    INDEX 94 03:42:54
+    INDEX 95 03:42:55
+    INDEX 96 03:42:56
+    INDEX 97 03:42:57
+    INDEX 98 03:42:58
+    INDEX 99 03:42:59
+    INDEX 100 04:00:00
diff --git a/test/cuesheets/bad.066.INDEX_missing_offset.cue b/test/cuesheets/bad.066.INDEX_missing_offset.cue
new file mode 100644
index 0000000..1e78bc6
--- /dev/null
+++ b/test/cuesheets/bad.066.INDEX_missing_offset.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 
diff --git a/test/cuesheets/bad.067.INDEX_illegal_offset.cue b/test/cuesheets/bad.067.INDEX_illegal_offset.cue
new file mode 100644
index 0000000..8742029
--- /dev/null
+++ b/test/cuesheets/bad.067.INDEX_illegal_offset.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:00.00
diff --git a/test/cuesheets/bad.068.INDEX_cdda_illegal_offset.cue b/test/cuesheets/bad.068.INDEX_cdda_illegal_offset.cue
new file mode 100644
index 0000000..6e00fed
--- /dev/null
+++ b/test/cuesheets/bad.068.INDEX_cdda_illegal_offset.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 588
diff --git a/test/cuesheets/bad.069.nonzero_first_INDEX.cue b/test/cuesheets/bad.069.nonzero_first_INDEX.cue
new file mode 100644
index 0000000..7464949
--- /dev/null
+++ b/test/cuesheets/bad.069.nonzero_first_INDEX.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:02:00
diff --git a/test/cuesheets/bad.070.INDEX_offset_not_ascending_1.cue b/test/cuesheets/bad.070.INDEX_offset_not_ascending_1.cue
new file mode 100644
index 0000000..a4fe063
--- /dev/null
+++ b/test/cuesheets/bad.070.INDEX_offset_not_ascending_1.cue
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+	INDEX 02 00:02:00
+	INDEX 03 00:01:74
diff --git a/test/cuesheets/bad.071.INDEX_offset_not_ascending_2.cue b/test/cuesheets/bad.071.INDEX_offset_not_ascending_2.cue
new file mode 100644
index 0000000..8983a03
--- /dev/null
+++ b/test/cuesheets/bad.071.INDEX_offset_not_ascending_2.cue
@@ -0,0 +1,6 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+    INDEX 02 00:02:00
+  TRACK 02 AUDIO
+    INDEX 01 00:01:74
diff --git a/test/cuesheets/bad.110.ISRC_multiple.cue b/test/cuesheets/bad.110.ISRC_multiple.cue
new file mode 100644
index 0000000..907c1b8
--- /dev/null
+++ b/test/cuesheets/bad.110.ISRC_multiple.cue
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    ISRC ABCDE1234567
+    ISRC ABCD01234567
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.111.ISRC_wrong_place_1.cue b/test/cuesheets/bad.111.ISRC_wrong_place_1.cue
new file mode 100644
index 0000000..86fbe90
--- /dev/null
+++ b/test/cuesheets/bad.111.ISRC_wrong_place_1.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+ISRC ABCD01234567
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.112.ISRC_wrong_place_2.cue b/test/cuesheets/bad.112.ISRC_wrong_place_2.cue
new file mode 100644
index 0000000..e0b4e77
--- /dev/null
+++ b/test/cuesheets/bad.112.ISRC_wrong_place_2.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+    ISRC ABCD01234567
diff --git a/test/cuesheets/bad.113.ISRC_missing_number.cue b/test/cuesheets/bad.113.ISRC_missing_number.cue
new file mode 100644
index 0000000..742e054
--- /dev/null
+++ b/test/cuesheets/bad.113.ISRC_missing_number.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    ISRC
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.114.ISRC_invalid_number.cue b/test/cuesheets/bad.114.ISRC_invalid_number.cue
new file mode 100644
index 0000000..362130a
--- /dev/null
+++ b/test/cuesheets/bad.114.ISRC_invalid_number.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    ISRC ABCD0123456Z
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.130.TRACK_missing_INDEX_01_1.cue b/test/cuesheets/bad.130.TRACK_missing_INDEX_01_1.cue
new file mode 100644
index 0000000..0697074
--- /dev/null
+++ b/test/cuesheets/bad.130.TRACK_missing_INDEX_01_1.cue
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
diff --git a/test/cuesheets/bad.131.TRACK_missing_INDEX_01_2.cue b/test/cuesheets/bad.131.TRACK_missing_INDEX_01_2.cue
new file mode 100644
index 0000000..554cf12
--- /dev/null
+++ b/test/cuesheets/bad.131.TRACK_missing_INDEX_01_2.cue
@@ -0,0 +1,3 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 00 00:00:00
diff --git a/test/cuesheets/bad.132.TRACK_missing_INDEX_01_3.cue b/test/cuesheets/bad.132.TRACK_missing_INDEX_01_3.cue
new file mode 100644
index 0000000..5618db8
--- /dev/null
+++ b/test/cuesheets/bad.132.TRACK_missing_INDEX_01_3.cue
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+  TRACK 02 AUDIO
+    INDEX 01 00:02:00
diff --git a/test/cuesheets/bad.133.TRACK_missing_INDEX_01_4.cue b/test/cuesheets/bad.133.TRACK_missing_INDEX_01_4.cue
new file mode 100644
index 0000000..f74a9e4
--- /dev/null
+++ b/test/cuesheets/bad.133.TRACK_missing_INDEX_01_4.cue
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 00 00:00:00
+  TRACK 02 AUDIO
+    INDEX 01 00:02:00
diff --git a/test/cuesheets/bad.134.TRACK_missing_number.cue b/test/cuesheets/bad.134.TRACK_missing_number.cue
new file mode 100644
index 0000000..f95180b
--- /dev/null
+++ b/test/cuesheets/bad.134.TRACK_missing_number.cue
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 
diff --git a/test/cuesheets/bad.135.TRACK_invalid_number_1.cue b/test/cuesheets/bad.135.TRACK_invalid_number_1.cue
new file mode 100644
index 0000000..9c3c9ea
--- /dev/null
+++ b/test/cuesheets/bad.135.TRACK_invalid_number_1.cue
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK thhpt! AUDIO
diff --git a/test/cuesheets/bad.136.TRACK_invalid_number_2.cue b/test/cuesheets/bad.136.TRACK_invalid_number_2.cue
new file mode 100644
index 0000000..69caafa
--- /dev/null
+++ b/test/cuesheets/bad.136.TRACK_invalid_number_2.cue
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 0 AUDIO
diff --git a/test/cuesheets/bad.137.TRACK_cdda_out_of_range.cue b/test/cuesheets/bad.137.TRACK_cdda_out_of_range.cue
new file mode 100644
index 0000000..8696f52
--- /dev/null
+++ b/test/cuesheets/bad.137.TRACK_cdda_out_of_range.cue
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 100 AUDIO
diff --git a/test/cuesheets/bad.138.TRACK_num_non_sequential.cue b/test/cuesheets/bad.138.TRACK_num_non_sequential.cue
new file mode 100644
index 0000000..37870c3
--- /dev/null
+++ b/test/cuesheets/bad.138.TRACK_num_non_sequential.cue
@@ -0,0 +1,6 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 0:0:0
+  TRACK 02 AUDIO
+    INDEX 01 2:0:0
+  TRACK 01 AUDIO
diff --git a/test/cuesheets/bad.139.TRACK_missing_type.cue b/test/cuesheets/bad.139.TRACK_missing_type.cue
new file mode 100644
index 0000000..01fca6a
--- /dev/null
+++ b/test/cuesheets/bad.139.TRACK_missing_type.cue
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 01
diff --git a/test/cuesheets/bad.140.no_TRACKs.cue b/test/cuesheets/bad.140.no_TRACKs.cue
new file mode 100644
index 0000000..73cb8cf
--- /dev/null
+++ b/test/cuesheets/bad.140.no_TRACKs.cue
@@ -0,0 +1 @@
+FILE "z.wav" WAVE
diff --git a/test/cuesheets/bad.200.FLAC_leadin_missing_offset.cue b/test/cuesheets/bad.200.FLAC_leadin_missing_offset.cue
new file mode 100644
index 0000000..7441aa5
--- /dev/null
+++ b/test/cuesheets/bad.200.FLAC_leadin_missing_offset.cue
@@ -0,0 +1 @@
+REM FLAC__lead-in
diff --git a/test/cuesheets/bad.201.FLAC_leadin_illegal_offset.cue b/test/cuesheets/bad.201.FLAC_leadin_illegal_offset.cue
new file mode 100644
index 0000000..acf6940
--- /dev/null
+++ b/test/cuesheets/bad.201.FLAC_leadin_illegal_offset.cue
@@ -0,0 +1 @@
+REM FLAC__lead-in thhpt!
diff --git a/test/cuesheets/bad.202.FLAC_leadin_cdda_illegal_offset.cue b/test/cuesheets/bad.202.FLAC_leadin_cdda_illegal_offset.cue
new file mode 100644
index 0000000..6f2d0f7
--- /dev/null
+++ b/test/cuesheets/bad.202.FLAC_leadin_cdda_illegal_offset.cue
@@ -0,0 +1 @@
+REM FLAC__lead-in 123
diff --git a/test/cuesheets/bad.230.FLAC_leadout_multiple.cue b/test/cuesheets/bad.230.FLAC_leadout_multiple.cue
new file mode 100644
index 0000000..656fe9d
--- /dev/null
+++ b/test/cuesheets/bad.230.FLAC_leadout_multiple.cue
@@ -0,0 +1,3 @@
+REM FLAC__lead-in 88200
+REM FLAC__lead-out 170 211680000
+REM FLAC__lead-out 170 211680588
diff --git a/test/cuesheets/bad.231.FLAC_leadout_missing_track.cue b/test/cuesheets/bad.231.FLAC_leadout_missing_track.cue
new file mode 100644
index 0000000..a723b7a
--- /dev/null
+++ b/test/cuesheets/bad.231.FLAC_leadout_missing_track.cue
@@ -0,0 +1 @@
+REM FLAC__lead-out 
diff --git a/test/cuesheets/bad.232.FLAC_leadout_illegal_track.cue b/test/cuesheets/bad.232.FLAC_leadout_illegal_track.cue
new file mode 100644
index 0000000..6001826
--- /dev/null
+++ b/test/cuesheets/bad.232.FLAC_leadout_illegal_track.cue
@@ -0,0 +1 @@
+REM FLAC__lead-out thhpt!
diff --git a/test/cuesheets/bad.233.FLAC_leadout_missing_offset.cue b/test/cuesheets/bad.233.FLAC_leadout_missing_offset.cue
new file mode 100644
index 0000000..ef5f1dc
--- /dev/null
+++ b/test/cuesheets/bad.233.FLAC_leadout_missing_offset.cue
@@ -0,0 +1 @@
+REM FLAC__lead-out 170
diff --git a/test/cuesheets/bad.234.FLAC_leadout_illegal_offset.cue b/test/cuesheets/bad.234.FLAC_leadout_illegal_offset.cue
new file mode 100644
index 0000000..01c69f4
--- /dev/null
+++ b/test/cuesheets/bad.234.FLAC_leadout_illegal_offset.cue
@@ -0,0 +1 @@
+REM FLAC__lead-out 170 thhpt!
diff --git a/test/cuesheets/bad.235.FLAC_leadout_offset_not_211680000.cue b/test/cuesheets/bad.235.FLAC_leadout_offset_not_211680000.cue
new file mode 100644
index 0000000..8add1d6
--- /dev/null
+++ b/test/cuesheets/bad.235.FLAC_leadout_offset_not_211680000.cue
@@ -0,0 +1 @@
+REM FLAC__lead-out 170 211680588
diff --git a/test/cuesheets/good.000.cue b/test/cuesheets/good.000.cue
new file mode 100644
index 0000000..bdfbccf
--- /dev/null
+++ b/test/cuesheets/good.000.cue
@@ -0,0 +1,4 @@
+CATALOG "1234567890123"
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/good.001.cue b/test/cuesheets/good.001.cue
new file mode 100644
index 0000000..f9887cf
--- /dev/null
+++ b/test/cuesheets/good.001.cue
@@ -0,0 +1,184 @@
+REM FLAC__lead-in 88200
+REM FLAC__lead-out 170 211680000
+CATALOG 1234567890123
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:00:00
+  TRACK 02 AUDIO
+    FLAGS PRE
+    ISRC ABCDE7654321
+    INDEX 00 02:09:12
+    INDEX 01 02:10:15
+    INDEX 02 02:20:15
+    INDEX 03 02:30:15
+    INDEX 04 03:30:15
+    INDEX 05 03:31:15
+    INDEX 06 03:32:06
+    INDEX 07 03:32:07
+    INDEX 08 03:32:08
+    INDEX 09 03:32:09
+    INDEX 10 03:32:10
+    INDEX 11 03:32:11
+    INDEX 12 03:32:12
+    INDEX 13 03:32:13
+    INDEX 14 03:32:14
+    INDEX 15 03:32:15
+    INDEX 16 03:32:16
+    INDEX 17 03:32:17
+    INDEX 18 03:32:18
+    INDEX 19 03:32:19
+    INDEX 20 03:32:20
+    INDEX 21 03:32:21
+    INDEX 22 03:32:22
+    INDEX 23 03:32:23
+    INDEX 24 03:32:24
+    INDEX 25 03:32:25
+    INDEX 26 03:32:26
+    INDEX 27 03:32:27
+    INDEX 28 03:32:28
+    INDEX 29 03:32:29
+    INDEX 30 03:32:30
+    INDEX 31 03:32:31
+    INDEX 32 03:32:32
+    INDEX 33 03:32:33
+    INDEX 34 03:32:34
+    INDEX 35 03:32:35
+    INDEX 36 03:32:36
+    INDEX 37 03:32:37
+    INDEX 38 03:32:38
+    INDEX 39 03:32:39
+    INDEX 40 03:32:40
+    INDEX 41 03:32:41
+    INDEX 42 03:32:42
+    INDEX 43 03:32:43
+    INDEX 44 03:32:44
+    INDEX 45 03:32:45
+    INDEX 46 03:32:46
+    INDEX 47 03:32:47
+    INDEX 48 03:32:48
+    INDEX 49 03:32:49
+    INDEX 50 03:32:50
+    INDEX 51 03:32:51
+    INDEX 52 03:32:52
+    INDEX 53 03:32:53
+    INDEX 54 03:32:54
+    INDEX 55 03:32:55
+    INDEX 56 03:32:56
+    INDEX 57 03:32:57
+    INDEX 58 03:32:58
+    INDEX 59 03:32:59
+    INDEX 60 03:32:60
+    INDEX 61 03:32:61
+    INDEX 62 03:32:62
+    INDEX 63 03:32:63
+    INDEX 64 03:32:64
+    INDEX 65 03:32:65
+    INDEX 66 03:32:66
+    INDEX 67 03:32:67
+    INDEX 68 03:32:68
+    INDEX 69 03:32:69
+    INDEX 70 03:40:50
+    INDEX 71 03:40:51
+    INDEX 72 03:40:52
+    INDEX 73 03:40:53
+    INDEX 74 03:40:54
+    INDEX 75 03:40:55
+    INDEX 76 03:40:56
+    INDEX 77 03:40:57
+    INDEX 78 03:40:58
+    INDEX 79 03:40:59
+    INDEX 80 03:41:50
+    INDEX 81 03:41:51
+    INDEX 82 03:41:52
+    INDEX 83 03:41:53
+    INDEX 84 03:41:54
+    INDEX 85 03:41:55
+    INDEX 86 03:41:56
+    INDEX 87 03:41:57
+    INDEX 88 03:41:58
+    INDEX 89 03:41:59
+    INDEX 90 03:42:50
+    INDEX 91 03:42:51
+    INDEX 92 03:42:52
+    INDEX 93 03:42:53
+    INDEX 94 03:42:54
+    INDEX 95 03:42:55
+    INDEX 96 03:42:56
+    INDEX 97 03:42:57
+    INDEX 98 03:42:58
+    INDEX 99 03:42:59
+  TRACK 03 AUDIO
+    ISRC AB-CD7-65-43210
+    INDEX 00 04:50:12
+    INDEX 01 04:51:72
+  TRACK 04 AUDIO
+    INDEX 00 06:36:10
+    INDEX 01 06:38:47
+  TRACK 05 AUDIO
+    INDEX 00 08:34:45
+    INDEX 01 08:36:15
+  TRACK 06 AUDIO
+    INDEX 00 13:20:22
+    INDEX 01 13:22:12
+  TRACK 07 AUDIO
+    INDEX 00 16:08:20
+    INDEX 01 16:11:17
+  TRACK 08 AUDIO
+    INDEX 01 17:48:37
+  TRACK 09 AUDIO
+    INDEX 00 19:38:17
+    INDEX 01 19:39:30
+  TRACK 10 AUDIO
+    INDEX 00 22:07:07
+    INDEX 01 22:08:20
+  TRACK 11 AUDIO
+    INDEX 01 24:16:45
+  TRACK 12 AUDIO
+    INDEX 01 26:13:67
+  TRACK 13 AUDIO
+    INDEX 01 28:03:27
+  TRACK 14 AUDIO
+    INDEX 00 30:22:42
+    INDEX 01 30:24:45
+  TRACK 15 AUDIO
+    INDEX 00 34:06:22
+    INDEX 01 34:07:62
+  TRACK 16 AUDIO
+    INDEX 00 35:54:30
+    INDEX 01 35:56:60
+  TRACK 17 AUDIO
+    INDEX 00 38:49:10
+    INDEX 01 38:51:22
+  TRACK 18 AUDIO
+    INDEX 00 41:14:15
+    INDEX 01 41:17:15
+  TRACK 19 AUDIO
+    INDEX 00 44:27:15
+    INDEX 01 44:28:45
+  TRACK 20 AUDIO
+    INDEX 00 48:07:17
+    INDEX 01 48:09:72
+  TRACK 21 AUDIO
+    INDEX 00 50:48:05
+    INDEX 01 50:49:27
+  TRACK 22 AUDIO
+    INDEX 00 53:29:72
+    INDEX 01 53:31:20
+  TRACK 23 AUDIO
+    INDEX 00 57:57:60
+    INDEX 01 58:00:40
+  TRACK 24 AUDIO
+    INDEX 00 61:52:65
+    INDEX 01 61:55:37
+  TRACK 25 AUDIO
+    INDEX 00 65:07:50
+    INDEX 01 65:10:52
+  TRACK 26 AUDIO
+    INDEX 00 68:30:05
+    INDEX 01 68:32:45
+  TRACK 27 AUDIO
+    INDEX 01 71:45:17
+  TRACK 28 AUDIO
+    INDEX 00 74:49:07
+    INDEX 01 74:51:47
diff --git a/test/cuesheets/good.002.dos_format.cue b/test/cuesheets/good.002.dos_format.cue
new file mode 100644
index 0000000..a60e03b
--- /dev/null
+++ b/test/cuesheets/good.002.dos_format.cue
@@ -0,0 +1,4 @@
+CATALOG "1234567890123"

+FILE "z.wav" WAVE

+  TRACK 01 AUDIO

+    INDEX 01 00:00:00

diff --git a/test/cuesheets/good.003.missing_final_newline.cue b/test/cuesheets/good.003.missing_final_newline.cue
new file mode 100644
index 0000000..a4c298f
--- /dev/null
+++ b/test/cuesheets/good.003.missing_final_newline.cue
@@ -0,0 +1,4 @@
+CATALOG "1234567890123"
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
\ No newline at end of file
diff --git a/test/cuesheets/good.004.dos_format.missing_final_newline.cue b/test/cuesheets/good.004.dos_format.missing_final_newline.cue
new file mode 100644
index 0000000..1f6d0e5
--- /dev/null
+++ b/test/cuesheets/good.004.dos_format.missing_final_newline.cue
@@ -0,0 +1,4 @@
+CATALOG "1234567890123"

+FILE "z.wav" WAVE

+  TRACK 01 AUDIO

+    INDEX 01 00:00:00
\ No newline at end of file
diff --git a/test/cuesheets/good.005.quoted.isrc.cue b/test/cuesheets/good.005.quoted.isrc.cue
new file mode 100644
index 0000000..3d8e905
--- /dev/null
+++ b/test/cuesheets/good.005.quoted.isrc.cue
@@ -0,0 +1,6 @@
+TRACK 01 AUDIO

+TITLE "Foo"

+PERFORMER "Bar"

+DISC_ID ""

+ISRC "US-SM1-23-45678"

+INDEX 01 00:00:00

diff --git a/test/flac-to-flac-metadata-test-files/Makefile.am b/test/flac-to-flac-metadata-test-files/Makefile.am
new file mode 100644
index 0000000..fc96f82
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/Makefile.am
@@ -0,0 +1,46 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2006-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+	case00a-expect.meta \
+	case01a-expect.meta \
+	case01b-expect.meta \
+	case01c-expect.meta \
+	case01d-expect.meta \
+	case01e-expect.meta \
+	case02a-expect.meta \
+	case02b-expect.meta \
+	case02c-expect.meta \
+	case03a-expect.meta \
+	case03b-expect.meta \
+	case03c-expect.meta \
+	case04a-expect.meta \
+	case04b-expect.meta \
+	case04c-expect.meta \
+	case04d-expect.meta \
+	case04e-expect.meta \
+	input-SCPAP.flac \
+	input-SCVA.flac \
+	input-SCVAUP.flac \
+	input-SCVPAP.flac \
+	input-SVAUP.flac \
+	input-VA.flac \
+	input0.cue
+
+clean-local:
+	-rm -f out.*
diff --git a/test/flac-to-flac-metadata-test-files/case00a-expect.meta b/test/flac-to-flac-metadata-test-files/case00a-expect.meta
new file mode 100644
index 0000000..6facc3e
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case00a-expect.meta
@@ -0,0 +1,84 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 126 (UNKNOWN)
+  is last: false
+  length: XXX
+  data contents:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case01a-expect.meta b/test/flac-to-flac-metadata-test-files/case01a-expect.meta
new file mode 100644
index 0000000..25ceaec
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case01a-expect.meta
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case01b-expect.meta b/test/flac-to-flac-metadata-test-files/case01b-expect.meta
new file mode 100644
index 0000000..1970646
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case01b-expect.meta
@@ -0,0 +1,75 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: true
+  length: XXX
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case01c-expect.meta b/test/flac-to-flac-metadata-test-files/case01c-expect.meta
new file mode 100644
index 0000000..25ceaec
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case01c-expect.meta
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case01d-expect.meta b/test/flac-to-flac-metadata-test-files/case01d-expect.meta
new file mode 100644
index 0000000..25ceaec
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case01d-expect.meta
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case01e-expect.meta b/test/flac-to-flac-metadata-test-files/case01e-expect.meta
new file mode 100644
index 0000000..25ceaec
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case01e-expect.meta
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case02a-expect.meta b/test/flac-to-flac-metadata-test-files/case02a-expect.meta
new file mode 100644
index 0000000..63bf6f6
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case02a-expect.meta
@@ -0,0 +1,73 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 0
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case02b-expect.meta b/test/flac-to-flac-metadata-test-files/case02b-expect.meta
new file mode 100644
index 0000000..a6b269d
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case02b-expect.meta
@@ -0,0 +1,74 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: artist=0
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case02c-expect.meta b/test/flac-to-flac-metadata-test-files/case02c-expect.meta
new file mode 100644
index 0000000..2e2e06f
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case02c-expect.meta
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: artist=0
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 126 (UNKNOWN)
+  is last: false
+  length: XXX
+  data contents:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case03a-expect.meta b/test/flac-to-flac-metadata-test-files/case03a-expect.meta
new file mode 100644
index 0000000..c4c4c93
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case03a-expect.meta
@@ -0,0 +1,84 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 9294969890929
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 588
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 2352
+          number: 2
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 126 (UNKNOWN)
+  is last: false
+  length: XXX
+  data contents:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case03b-expect.meta b/test/flac-to-flac-metadata-test-files/case03b-expect.meta
new file mode 100644
index 0000000..c4c4c93
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case03b-expect.meta
@@ -0,0 +1,84 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 9294969890929
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 588
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 2352
+          number: 2
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 126 (UNKNOWN)
+  is last: false
+  length: XXX
+  data contents:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case03c-expect.meta b/test/flac-to-flac-metadata-test-files/case03c-expect.meta
new file mode 100644
index 0000000..6bdefb3
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case03c-expect.meta
@@ -0,0 +1,41 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5879
+  MD5 signature: 2ea0e6a767b66bf0668523fd77672ce1
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #3
+  type: 2 (APPLICATION)
+  is last: false
+  length: XXX
+  application ID: 66616b65
+  data contents:
+METADATA block #4
+  type: 126 (UNKNOWN)
+  is last: false
+  length: XXX
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/flac-to-flac-metadata-test-files/case04a-expect.meta b/test/flac-to-flac-metadata-test-files/case04a-expect.meta
new file mode 100644
index 0000000..cb50bb4
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case04a-expect.meta
@@ -0,0 +1,26 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #2
+  type: 2 (APPLICATION)
+  is last: true
+  length: XXX
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case04b-expect.meta b/test/flac-to-flac-metadata-test-files/case04b-expect.meta
new file mode 100644
index 0000000..71d9b95
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case04b-expect.meta
@@ -0,0 +1,36 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 5
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #3
+  type: 2 (APPLICATION)
+  is last: true
+  length: XXX
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case04c-expect.meta b/test/flac-to-flac-metadata-test-files/case04c-expect.meta
new file mode 100644
index 0000000..f163edf
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case04c-expect.meta
@@ -0,0 +1,32 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #3
+  type: 2 (APPLICATION)
+  is last: true
+  length: XXX
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case04d-expect.meta b/test/flac-to-flac-metadata-test-files/case04d-expect.meta
new file mode 100644
index 0000000..086f684
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case04d-expect.meta
@@ -0,0 +1,60 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #3
+  type: 2 (APPLICATION)
+  is last: true
+  length: XXX
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case04e-expect.meta b/test/flac-to-flac-metadata-test-files/case04e-expect.meta
new file mode 100644
index 0000000..6559840
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/case04e-expect.meta
@@ -0,0 +1,70 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 5
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: true
+  length: XXX
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/input-SCPAP.flac b/test/flac-to-flac-metadata-test-files/input-SCPAP.flac
new file mode 100644
index 0000000..6fde318
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/input-SCPAP.flac
Binary files differ
diff --git a/test/flac-to-flac-metadata-test-files/input-SCVA.flac b/test/flac-to-flac-metadata-test-files/input-SCVA.flac
new file mode 100644
index 0000000..4bb6926
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/input-SCVA.flac
Binary files differ
diff --git a/test/flac-to-flac-metadata-test-files/input-SCVAUP.flac b/test/flac-to-flac-metadata-test-files/input-SCVAUP.flac
new file mode 100644
index 0000000..e4ecc95
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/input-SCVAUP.flac
Binary files differ
diff --git a/test/flac-to-flac-metadata-test-files/input-SCVPAP.flac b/test/flac-to-flac-metadata-test-files/input-SCVPAP.flac
new file mode 100644
index 0000000..7474928
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/input-SCVPAP.flac
Binary files differ
diff --git a/test/flac-to-flac-metadata-test-files/input-SVAUP.flac b/test/flac-to-flac-metadata-test-files/input-SVAUP.flac
new file mode 100644
index 0000000..e3fa5c1
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/input-SVAUP.flac
Binary files differ
diff --git a/test/flac-to-flac-metadata-test-files/input-VA.flac b/test/flac-to-flac-metadata-test-files/input-VA.flac
new file mode 100644
index 0000000..4fac878
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/input-VA.flac
Binary files differ
diff --git a/test/flac-to-flac-metadata-test-files/input0.cue b/test/flac-to-flac-metadata-test-files/input0.cue
new file mode 100644
index 0000000..2894bd0
--- /dev/null
+++ b/test/flac-to-flac-metadata-test-files/input0.cue
@@ -0,0 +1,7 @@
+CATALOG 9294969890929
+FILE "blah" FLAC
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+  TRACK 02 AUDIO
+    INDEX 01 00:00:01
+    INDEX 02 00:00:05
diff --git a/test/metaflac-test-files/Makefile.am b/test/metaflac-test-files/Makefile.am
new file mode 100644
index 0000000..adcb34a
--- /dev/null
+++ b/test/metaflac-test-files/Makefile.am
@@ -0,0 +1,85 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2006-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+	case00-expect.meta \
+	case01-expect.meta \
+	case02-expect.meta \
+	case03-expect.meta \
+	case04-expect.meta \
+	case05-expect.meta \
+	case06-expect.meta \
+	case07-expect.meta \
+	case08-expect.meta \
+	case09-expect.meta \
+	case10-expect.meta \
+	case11-expect.meta \
+	case12-expect.meta \
+	case13-expect.meta \
+	case14-expect.meta \
+	case15-expect.meta \
+	case16-expect.meta \
+	case17-expect.meta \
+	case18-expect.meta \
+	case19-expect.meta \
+	case20-expect.meta \
+	case21-expect.meta \
+	case22-expect.meta \
+	case23-expect.meta \
+	case24-expect.meta \
+	case25-expect.meta \
+	case26-expect.meta \
+	case27-expect.meta \
+	case28-expect.meta \
+	case29-expect.meta \
+	case30-expect.meta \
+	case31-expect.meta \
+	case32-expect.meta \
+	case33-expect.meta \
+	case34-expect.meta \
+	case35-expect.meta \
+	case36-expect.meta \
+	case37-expect.meta \
+	case38-expect.meta \
+	case39-expect.meta \
+	case40-expect.meta \
+	case41-expect.meta \
+	case42-expect.meta \
+	case43-expect.meta \
+	case44-expect.meta \
+	case45-expect.meta \
+	case46-expect.meta \
+	case47-expect.meta \
+	case48-expect.meta \
+	case49-expect.meta \
+	case50-expect.meta \
+	case51-expect.meta \
+	case52-expect.meta \
+	case53-expect.meta \
+	case54-expect.meta \
+	case55-expect.meta \
+	case56-expect.meta \
+	case57-expect.meta \
+	case58-expect.meta \
+	case59-expect.meta \
+	case60-expect.meta \
+	case61-expect.meta \
+	case62-expect.meta
+
+clean-local:
+	-rm -f out.*
diff --git a/test/metaflac-test-files/case00-expect.meta b/test/metaflac-test-files/case00-expect.meta
new file mode 100644
index 0000000..a1a3770
--- /dev/null
+++ b/test/metaflac-test-files/case00-expect.meta
@@ -0,0 +1,24 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 0
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case01-expect.meta b/test/metaflac-test-files/case01-expect.meta
new file mode 100644
index 0000000..bae8f49
--- /dev/null
+++ b/test/metaflac-test-files/case01-expect.meta
@@ -0,0 +1,9 @@
+a042237c5493fdb9656b94a83608d11a
+1152
+1152
+10
+10
+8000
+1
+8
+80000
diff --git a/test/metaflac-test-files/case02-expect.meta b/test/metaflac-test-files/case02-expect.meta
new file mode 100644
index 0000000..830302c
--- /dev/null
+++ b/test/metaflac-test-files/case02-expect.meta
@@ -0,0 +1,28 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 0
+METADATA block #3
+  type: 1 (PADDING)
+  is last: false
+  length: XXX
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case03-expect.meta b/test/metaflac-test-files/case03-expect.meta
new file mode 100644
index 0000000..a3b88bd
--- /dev/null
+++ b/test/metaflac-test-files/case03-expect.meta
@@ -0,0 +1,25 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: ARTIST=The_artist_formerly_known_as_the_artist...
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case04-expect.meta b/test/metaflac-test-files/case04-expect.meta
new file mode 100644
index 0000000..056f5af
--- /dev/null
+++ b/test/metaflac-test-files/case04-expect.meta
@@ -0,0 +1,26 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 2
+    comment[0]: ARTIST=The_artist_formerly_known_as_the_artist...
+    comment[1]: ARTIST=Chuck_Woolery
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case05-expect.meta b/test/metaflac-test-files/case05-expect.meta
new file mode 100644
index 0000000..6bc0238
--- /dev/null
+++ b/test/metaflac-test-files/case05-expect.meta
@@ -0,0 +1,27 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 3
+    comment[0]: ARTIST=The_artist_formerly_known_as_the_artist...
+    comment[1]: ARTIST=Chuck_Woolery
+    comment[2]: ARTIST=Vern
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case06-expect.meta b/test/metaflac-test-files/case06-expect.meta
new file mode 100644
index 0000000..7435329
--- /dev/null
+++ b/test/metaflac-test-files/case06-expect.meta
@@ -0,0 +1,28 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: ARTIST=The_artist_formerly_known_as_the_artist...
+    comment[1]: ARTIST=Chuck_Woolery
+    comment[2]: ARTIST=Vern
+    comment[3]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case07-expect.meta b/test/metaflac-test-files/case07-expect.meta
new file mode 100644
index 0000000..5612e04
--- /dev/null
+++ b/test/metaflac-test-files/case07-expect.meta
@@ -0,0 +1,4 @@
+reference libFLAC 1.3.3 20190804
+ARTIST=The_artist_formerly_known_as_the_artist...
+ARTIST=Chuck_Woolery
+ARTIST=Vern
diff --git a/test/metaflac-test-files/case08-expect.meta b/test/metaflac-test-files/case08-expect.meta
new file mode 100644
index 0000000..61845ae
--- /dev/null
+++ b/test/metaflac-test-files/case08-expect.meta
@@ -0,0 +1,27 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 3
+    comment[0]: ARTIST=Chuck_Woolery
+    comment[1]: ARTIST=Vern
+    comment[2]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case09-expect.meta b/test/metaflac-test-files/case09-expect.meta
new file mode 100644
index 0000000..71f7270
--- /dev/null
+++ b/test/metaflac-test-files/case09-expect.meta
@@ -0,0 +1,25 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case10-expect.meta b/test/metaflac-test-files/case10-expect.meta
new file mode 100644
index 0000000..402ad6d
--- /dev/null
+++ b/test/metaflac-test-files/case10-expect.meta
@@ -0,0 +1,6 @@
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
diff --git a/test/metaflac-test-files/case11-expect.meta b/test/metaflac-test-files/case11-expect.meta
new file mode 100644
index 0000000..530001b
--- /dev/null
+++ b/test/metaflac-test-files/case11-expect.meta
@@ -0,0 +1,9 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
diff --git a/test/metaflac-test-files/case12-expect.meta b/test/metaflac-test-files/case12-expect.meta
new file mode 100644
index 0000000..1d29f44
--- /dev/null
+++ b/test/metaflac-test-files/case12-expect.meta
@@ -0,0 +1,12 @@
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
diff --git a/test/metaflac-test-files/case13-expect.meta b/test/metaflac-test-files/case13-expect.meta
new file mode 100644
index 0000000..004104f
--- /dev/null
+++ b/test/metaflac-test-files/case13-expect.meta
@@ -0,0 +1,10 @@
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case14-expect.meta b/test/metaflac-test-files/case14-expect.meta
new file mode 100644
index 0000000..a9a1167
--- /dev/null
+++ b/test/metaflac-test-files/case14-expect.meta
@@ -0,0 +1,13 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case15-expect.meta b/test/metaflac-test-files/case15-expect.meta
new file mode 100644
index 0000000..6f68176
--- /dev/null
+++ b/test/metaflac-test-files/case15-expect.meta
@@ -0,0 +1,16 @@
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case16-expect.meta b/test/metaflac-test-files/case16-expect.meta
new file mode 100644
index 0000000..28eaf2b
--- /dev/null
+++ b/test/metaflac-test-files/case16-expect.meta
@@ -0,0 +1,33 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: false
+  length: XXX
+METADATA block #4
+  type: 1 (PADDING)
+  is last: false
+  length: XXX
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case17-expect.meta b/test/metaflac-test-files/case17-expect.meta
new file mode 100644
index 0000000..71f7270
--- /dev/null
+++ b/test/metaflac-test-files/case17-expect.meta
@@ -0,0 +1,25 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case18-expect.meta b/test/metaflac-test-files/case18-expect.meta
new file mode 100644
index 0000000..81f1f0e
--- /dev/null
+++ b/test/metaflac-test-files/case18-expect.meta
@@ -0,0 +1,29 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: false
+  length: XXX
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case19-expect.meta b/test/metaflac-test-files/case19-expect.meta
new file mode 100644
index 0000000..71f7270
--- /dev/null
+++ b/test/metaflac-test-files/case19-expect.meta
@@ -0,0 +1,25 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case20-expect.meta b/test/metaflac-test-files/case20-expect.meta
new file mode 100644
index 0000000..81f1f0e
--- /dev/null
+++ b/test/metaflac-test-files/case20-expect.meta
@@ -0,0 +1,29 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: false
+  length: XXX
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case21-expect.meta b/test/metaflac-test-files/case21-expect.meta
new file mode 100644
index 0000000..a1a3770
--- /dev/null
+++ b/test/metaflac-test-files/case21-expect.meta
@@ -0,0 +1,24 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 0
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case22-expect.meta b/test/metaflac-test-files/case22-expect.meta
new file mode 100644
index 0000000..d102550
--- /dev/null
+++ b/test/metaflac-test-files/case22-expect.meta
@@ -0,0 +1,18 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case23-expect.meta b/test/metaflac-test-files/case23-expect.meta
new file mode 100644
index 0000000..d102550
--- /dev/null
+++ b/test/metaflac-test-files/case23-expect.meta
@@ -0,0 +1,18 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case24-expect.meta b/test/metaflac-test-files/case24-expect.meta
new file mode 100644
index 0000000..d102550
--- /dev/null
+++ b/test/metaflac-test-files/case24-expect.meta
@@ -0,0 +1,18 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case25-expect.meta b/test/metaflac-test-files/case25-expect.meta
new file mode 100644
index 0000000..79de56e
--- /dev/null
+++ b/test/metaflac-test-files/case25-expect.meta
@@ -0,0 +1,14 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: true
+  length: XXX
+  comments: 0
diff --git a/test/metaflac-test-files/case26-expect.meta b/test/metaflac-test-files/case26-expect.meta
new file mode 100644
index 0000000..622d19a
--- /dev/null
+++ b/test/metaflac-test-files/case26-expect.meta
@@ -0,0 +1,22 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: false
+  length: XXX
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case27-expect.meta b/test/metaflac-test-files/case27-expect.meta
new file mode 100644
index 0000000..1fd3fb6
--- /dev/null
+++ b/test/metaflac-test-files/case27-expect.meta
@@ -0,0 +1,13 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case28-expect.meta b/test/metaflac-test-files/case28-expect.meta
new file mode 100644
index 0000000..1fd3fb6
--- /dev/null
+++ b/test/metaflac-test-files/case28-expect.meta
@@ -0,0 +1,13 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case29-expect.meta b/test/metaflac-test-files/case29-expect.meta
new file mode 100644
index 0000000..0ebcd92
--- /dev/null
+++ b/test/metaflac-test-files/case29-expect.meta
@@ -0,0 +1,9 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: true
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
diff --git a/test/metaflac-test-files/case30-expect.meta b/test/metaflac-test-files/case30-expect.meta
new file mode 100644
index 0000000..0ebcd92
--- /dev/null
+++ b/test/metaflac-test-files/case30-expect.meta
@@ -0,0 +1,9 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: true
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
diff --git a/test/metaflac-test-files/case31-expect.meta b/test/metaflac-test-files/case31-expect.meta
new file mode 100644
index 0000000..a76e485
--- /dev/null
+++ b/test/metaflac-test-files/case31-expect.meta
@@ -0,0 +1,15 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: true
+  length: XXX
+  comments: 1
+    comment[0]: f=0123456789abcdefghij
diff --git a/test/metaflac-test-files/case32-expect.meta b/test/metaflac-test-files/case32-expect.meta
new file mode 100644
index 0000000..ad58596
--- /dev/null
+++ b/test/metaflac-test-files/case32-expect.meta
@@ -0,0 +1,15 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: true
+  length: XXX
+  comments: 1
+    comment[0]: f=0123456789abcdefghi
diff --git a/test/metaflac-test-files/case33-expect.meta b/test/metaflac-test-files/case33-expect.meta
new file mode 100644
index 0000000..aed7927
--- /dev/null
+++ b/test/metaflac-test-files/case33-expect.meta
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: f=0123456789abcde
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case34-expect.meta b/test/metaflac-test-files/case34-expect.meta
new file mode 100644
index 0000000..619bbcc
--- /dev/null
+++ b/test/metaflac-test-files/case34-expect.meta
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: f=0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case35-expect.meta b/test/metaflac-test-files/case35-expect.meta
new file mode 100644
index 0000000..274076d
--- /dev/null
+++ b/test/metaflac-test-files/case35-expect.meta
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: f=0123456789
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case36-expect.meta b/test/metaflac-test-files/case36-expect.meta
new file mode 100644
index 0000000..ad58596
--- /dev/null
+++ b/test/metaflac-test-files/case36-expect.meta
@@ -0,0 +1,15 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: true
+  length: XXX
+  comments: 1
+    comment[0]: f=0123456789abcdefghi
diff --git a/test/metaflac-test-files/case37-expect.meta b/test/metaflac-test-files/case37-expect.meta
new file mode 100644
index 0000000..274076d
--- /dev/null
+++ b/test/metaflac-test-files/case37-expect.meta
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: f=0123456789
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case38-expect.meta b/test/metaflac-test-files/case38-expect.meta
new file mode 100644
index 0000000..d6c3f79
--- /dev/null
+++ b/test/metaflac-test-files/case38-expect.meta
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 1
+    comment[0]: f=0123456789abcdefghij
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case39-expect.meta b/test/metaflac-test-files/case39-expect.meta
new file mode 100644
index 0000000..937f252
--- /dev/null
+++ b/test/metaflac-test-files/case39-expect.meta
@@ -0,0 +1,20 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 2
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case40-expect.meta b/test/metaflac-test-files/case40-expect.meta
new file mode 100644
index 0000000..f163537
--- /dev/null
+++ b/test/metaflac-test-files/case40-expect.meta
@@ -0,0 +1,22 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case41-expect.meta b/test/metaflac-test-files/case41-expect.meta
new file mode 100644
index 0000000..d2acc4b
--- /dev/null
+++ b/test/metaflac-test-files/case41-expect.meta
@@ -0,0 +1,27 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 9
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+    comment[4]: REPLAYGAIN_REFERENCE_LOUDNESS=89.0 dB
+    comment[5]: REPLAYGAIN_TRACK_GAIN=+64.82 dB
+    comment[6]: REPLAYGAIN_TRACK_PEAK=0.00000000
+    comment[7]: REPLAYGAIN_ALBUM_GAIN=+64.82 dB
+    comment[8]: REPLAYGAIN_ALBUM_PEAK=0.00000000
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case42-expect.meta b/test/metaflac-test-files/case42-expect.meta
new file mode 100644
index 0000000..f163537
--- /dev/null
+++ b/test/metaflac-test-files/case42-expect.meta
@@ -0,0 +1,22 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case43-expect.meta b/test/metaflac-test-files/case43-expect.meta
new file mode 100644
index 0000000..3bead39
--- /dev/null
+++ b/test/metaflac-test-files/case43-expect.meta
@@ -0,0 +1,49 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case44-expect.meta b/test/metaflac-test-files/case44-expect.meta
new file mode 100644
index 0000000..776daa5
--- /dev/null
+++ b/test/metaflac-test-files/case44-expect.meta
@@ -0,0 +1,28 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case45-expect.meta b/test/metaflac-test-files/case45-expect.meta
new file mode 100644
index 0000000..3bead39
--- /dev/null
+++ b/test/metaflac-test-files/case45-expect.meta
@@ -0,0 +1,49 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case46-expect.meta b/test/metaflac-test-files/case46-expect.meta
new file mode 100644
index 0000000..25778cb
--- /dev/null
+++ b/test/metaflac-test-files/case46-expect.meta
@@ -0,0 +1,62 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case47-expect.meta b/test/metaflac-test-files/case47-expect.meta
new file mode 100644
index 0000000..096c430
--- /dev/null
+++ b/test/metaflac-test-files/case47-expect.meta
@@ -0,0 +1,75 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case48-expect.meta b/test/metaflac-test-files/case48-expect.meta
new file mode 100644
index 0000000..4055396
--- /dev/null
+++ b/test/metaflac-test-files/case48-expect.meta
@@ -0,0 +1,88 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case49-expect.meta b/test/metaflac-test-files/case49-expect.meta
new file mode 100644
index 0000000..56f7d5e
--- /dev/null
+++ b/test/metaflac-test-files/case49-expect.meta
@@ -0,0 +1,101 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case50-expect.meta b/test/metaflac-test-files/case50-expect.meta
new file mode 100644
index 0000000..868df7c
--- /dev/null
+++ b/test/metaflac-test-files/case50-expect.meta
@@ -0,0 +1,114 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case51-expect.meta b/test/metaflac-test-files/case51-expect.meta
new file mode 100644
index 0000000..c98eae4
--- /dev/null
+++ b/test/metaflac-test-files/case51-expect.meta
@@ -0,0 +1,127 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case52-expect.meta b/test/metaflac-test-files/case52-expect.meta
new file mode 100644
index 0000000..4053288
--- /dev/null
+++ b/test/metaflac-test-files/case52-expect.meta
@@ -0,0 +1,140 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #11
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case53-expect.meta b/test/metaflac-test-files/case53-expect.meta
new file mode 100644
index 0000000..9dc3ef5
--- /dev/null
+++ b/test/metaflac-test-files/case53-expect.meta
@@ -0,0 +1,153 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #12
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case54-expect.meta b/test/metaflac-test-files/case54-expect.meta
new file mode 100644
index 0000000..866cd36
--- /dev/null
+++ b/test/metaflac-test-files/case54-expect.meta
@@ -0,0 +1,166 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #13
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case55-expect.meta b/test/metaflac-test-files/case55-expect.meta
new file mode 100644
index 0000000..38058ea
--- /dev/null
+++ b/test/metaflac-test-files/case55-expect.meta
@@ -0,0 +1,179 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #14
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case56-expect.meta b/test/metaflac-test-files/case56-expect.meta
new file mode 100644
index 0000000..0bcf922
--- /dev/null
+++ b/test/metaflac-test-files/case56-expect.meta
@@ -0,0 +1,192 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #14
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 5.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #15
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case57-expect.meta b/test/metaflac-test-files/case57-expect.meta
new file mode 100644
index 0000000..546a600
--- /dev/null
+++ b/test/metaflac-test-files/case57-expect.meta
@@ -0,0 +1,205 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #14
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 5.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #15
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 6.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: XXX
+  data:
+METADATA block #16
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case58-expect.meta b/test/metaflac-test-files/case58-expect.meta
new file mode 100644
index 0000000..6496167
--- /dev/null
+++ b/test/metaflac-test-files/case58-expect.meta
@@ -0,0 +1,218 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #14
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 5.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #15
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 6.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: XXX
+  data:
+METADATA block #16
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 7.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: XXX
+  data:
+METADATA block #17
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case59-expect.meta b/test/metaflac-test-files/case59-expect.meta
new file mode 100644
index 0000000..cbe812d
--- /dev/null
+++ b/test/metaflac-test-files/case59-expect.meta
@@ -0,0 +1,231 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: XXX
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: XXX
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: XXX
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #14
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 5.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #15
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 6.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: XXX
+  data:
+METADATA block #16
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 7.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: XXX
+  data:
+METADATA block #17
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 8.png
+  width: 32
+  height: 32
+  depth: 32
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #18
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case60-expect.meta b/test/metaflac-test-files/case60-expect.meta
new file mode 100644
index 0000000..3bead39
--- /dev/null
+++ b/test/metaflac-test-files/case60-expect.meta
@@ -0,0 +1,49 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case61-expect.meta b/test/metaflac-test-files/case61-expect.meta
new file mode 100644
index 0000000..535cde3
--- /dev/null
+++ b/test/metaflac-test-files/case61-expect.meta
@@ -0,0 +1,62 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 1 (32x32 pixels 'file icon' (PNG only))
+  MIME type: image/png
+  description: standard_icon
+  width: 32
+  height: 32
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac-test-files/case62-expect.meta b/test/metaflac-test-files/case62-expect.meta
new file mode 100644
index 0000000..472fec3
--- /dev/null
+++ b/test/metaflac-test-files/case62-expect.meta
@@ -0,0 +1,75 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: XXX
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: XXX
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: XXX
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: XXX
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 1 (32x32 pixels 'file icon' (PNG only))
+  MIME type: image/png
+  description: standard_icon
+  width: 32
+  height: 32
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: XXX
+  type: 2 (Other file icon)
+  MIME type: image/png
+  description: icon
+  width: 64
+  height: 64
+  depth: 24
+  colors: 0 (unindexed)
+  data length: XXX
+  data:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: XXX
diff --git a/test/metaflac.flac.in b/test/metaflac.flac.in
new file mode 100644
index 0000000..7989263
--- /dev/null
+++ b/test/metaflac.flac.in
Binary files differ
diff --git a/test/metaflac.flac.ok b/test/metaflac.flac.ok
new file mode 100644
index 0000000..82ad84c
--- /dev/null
+++ b/test/metaflac.flac.ok
Binary files differ
diff --git a/test/picture.ok b/test/picture.ok
new file mode 100644
index 0000000..4b7e55d
--- /dev/null
+++ b/test/picture.ok
@@ -0,0 +1,42 @@
+
++++ grabbag unit test: picture
+
+testing grabbag__picture_parse_specification("")... OK (failed as expected, error: error opening picture file)
+testing grabbag__picture_parse_specification("||||")... OK (failed as expected: error opening picture file)
+testing grabbag__picture_parse_specification("|image/gif|||")... OK (failed as expected: error opening picture file)
+testing grabbag__picture_parse_specification("|image/gif|desc|320|0.gif")... OK (failed as expected: invalid picture specification: can't parse resolution/color part)
+testing grabbag__picture_parse_specification("|image/gif|desc|320x240|0.gif")... OK (failed as expected: invalid picture specification: can't parse resolution/color part)
+testing grabbag__picture_parse_specification("|image/gif|desc|320x240x9|")... OK (failed as expected: error opening picture file)
+testing grabbag__picture_parse_specification("|image/gif|desc|320x240x9/2345|0.gif")... OK (failed as expected: invalid picture specification: can't parse resolution/color part)
+testing grabbag__picture_parse_specification("1|-->|desc|32x24x9|0.gif")... OK (failed as expected: type 1 icon must be a 32x32 pixel PNG)
+testing grabbag__picture_parse_specification("|-->|desc||http://blah.blah.blah/z.gif")... OK (failed as expected: unable to extract resolution and color info from URL, user must set explicitly)
+testing grabbag__picture_parse_specification("|-->|desc|320x240x9|http://blah.blah.blah/z.gif")... OK
+testing grabbag__picture_parse_specification("pictures/0.gif")... OK
+testing grabbag__picture_parse_specification("pictures/1.gif")... OK
+testing grabbag__picture_parse_specification("pictures/2.gif")... OK
+testing grabbag__picture_parse_specification("pictures/0.jpg")... OK
+testing grabbag__picture_parse_specification("pictures/4.jpg")... OK
+testing grabbag__picture_parse_specification("pictures/0.png")... OK
+testing grabbag__picture_parse_specification("pictures/1.png")... OK
+testing grabbag__picture_parse_specification("pictures/2.png")... OK
+testing grabbag__picture_parse_specification("pictures/3.png")... OK
+testing grabbag__picture_parse_specification("pictures/4.png")... OK
+testing grabbag__picture_parse_specification("pictures/5.png")... OK
+testing grabbag__picture_parse_specification("pictures/6.png")... OK
+testing grabbag__picture_parse_specification("pictures/7.png")... OK
+testing grabbag__picture_parse_specification("pictures/8.png")... OK
+testing grabbag__picture_parse_specification("3|image/gif|||pictures/0.gif")... OK
+testing grabbag__picture_parse_specification("4|image/gif|||pictures/1.gif")... OK
+testing grabbag__picture_parse_specification("0|image/gif|||pictures/2.gif")... OK
+testing grabbag__picture_parse_specification("3|image/jpeg|||pictures/0.jpg")... OK
+testing grabbag__picture_parse_specification("3|image/jpeg|||pictures/4.jpg")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/0.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/1.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/2.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/3.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/4.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/5.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/6.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/7.png")... OK
+testing grabbag__picture_parse_specification("999|image/png|||pictures/8.png")... OK
+testing grabbag__picture_parse_specification("3|image/gif||320x240x3/2|pictures/0.gif")... OK
diff --git a/test/pictures/0.gif b/test/pictures/0.gif
new file mode 100644
index 0000000..c9f3d71
--- /dev/null
+++ b/test/pictures/0.gif
Binary files differ
diff --git a/test/pictures/0.jpg b/test/pictures/0.jpg
new file mode 100644
index 0000000..54b9a7c
--- /dev/null
+++ b/test/pictures/0.jpg
Binary files differ
diff --git a/test/pictures/0.png b/test/pictures/0.png
new file mode 100644
index 0000000..2f3ec80
--- /dev/null
+++ b/test/pictures/0.png
Binary files differ
diff --git a/test/pictures/1.gif b/test/pictures/1.gif
new file mode 100644
index 0000000..c40eeae
--- /dev/null
+++ b/test/pictures/1.gif
Binary files differ
diff --git a/test/pictures/1.png b/test/pictures/1.png
new file mode 100644
index 0000000..2b487c0
--- /dev/null
+++ b/test/pictures/1.png
Binary files differ
diff --git a/test/pictures/2.gif b/test/pictures/2.gif
new file mode 100644
index 0000000..632098b
--- /dev/null
+++ b/test/pictures/2.gif
Binary files differ
diff --git a/test/pictures/2.png b/test/pictures/2.png
new file mode 100644
index 0000000..a7ca42b
--- /dev/null
+++ b/test/pictures/2.png
Binary files differ
diff --git a/test/pictures/3.png b/test/pictures/3.png
new file mode 100644
index 0000000..9d117b6
--- /dev/null
+++ b/test/pictures/3.png
Binary files differ
diff --git a/test/pictures/4.jpg b/test/pictures/4.jpg
new file mode 100644
index 0000000..da78796
--- /dev/null
+++ b/test/pictures/4.jpg
Binary files differ
diff --git a/test/pictures/4.png b/test/pictures/4.png
new file mode 100644
index 0000000..72c0a45
--- /dev/null
+++ b/test/pictures/4.png
Binary files differ
diff --git a/test/pictures/5.png b/test/pictures/5.png
new file mode 100644
index 0000000..abefad5
--- /dev/null
+++ b/test/pictures/5.png
Binary files differ
diff --git a/test/pictures/6.png b/test/pictures/6.png
new file mode 100644
index 0000000..4953ceb
--- /dev/null
+++ b/test/pictures/6.png
Binary files differ
diff --git a/test/pictures/7.png b/test/pictures/7.png
new file mode 100644
index 0000000..c8934c1
--- /dev/null
+++ b/test/pictures/7.png
Binary files differ
diff --git a/test/pictures/8.png b/test/pictures/8.png
new file mode 100644
index 0000000..01e4118
--- /dev/null
+++ b/test/pictures/8.png
Binary files differ
diff --git a/test/pictures/Makefile.am b/test/pictures/Makefile.am
new file mode 100644
index 0000000..6322594
--- /dev/null
+++ b/test/pictures/Makefile.am
@@ -0,0 +1,33 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2006-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+	0.gif \
+	0.jpg \
+	0.png \
+	1.gif \
+	1.png \
+	2.gif \
+	2.png \
+	3.png \
+	4.jpg \
+	4.png \
+	5.png \
+	6.png \
+	7.png \
+	8.png
diff --git a/test/test_compression.sh b/test/test_compression.sh
new file mode 100755
index 0000000..e1191ad
--- /dev/null
+++ b/test/test_compression.sh
@@ -0,0 +1,46 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2012-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+PATH=`pwd`/../src/flac:$PATH
+
+echo "Using FLAC binary :" $(which flac)
+
+date=`date "+%Y%m%dT%H%M%S"`
+fname="comp${date}.flac"
+
+last_k=0
+last_size=$(wc -c < noisy-sine.wav)
+
+echo "Original file size ${last_size} bytes."
+
+for k in 0 1 2 3 4 5 6 7 8 ; do
+	flac${EXE} -${k} --silent noisy-sine.wav -o ${fname}
+	size=$(wc -c < ${fname})
+	echo "Compression level ${k}, file size ${size} bytes."
+	if test ${last_size} -lt ${size} ; then
+		echo "Error : Compression ${last_k} size ${last_size} >= compression ${k} size ${size}."
+		exit 1
+		fi
+	# Need this because OSX's 'wc -c' returns a number with leading whitespace.
+	last_size=$((${size}+10))
+	last_k=${k}
+	rm -f ${fname}
+	done
diff --git a/test/test_flac.sh b/test/test_flac.sh
new file mode 100755
index 0000000..cd17b16
--- /dev/null
+++ b/test/test_flac.sh
@@ -0,0 +1,1256 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+# we use '.' as decimal separator in --skip/--until tests
+export LANG=C LC_ALL=C
+
+dddie="die ERROR: creating files with dd"
+
+PATH=`pwd`/../src/flac:$PATH
+PATH=`pwd`/../src/metaflac:$PATH
+PATH=`pwd`/../src/test_streams:$PATH
+PATH=`pwd`/../objs/$BUILD/bin:$PATH
+
+flac${EXE} --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+
+run_flac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 flac $*" >>test_flac.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 flac${EXE} $TOTALLY_SILENT --no-error-on-compression-fail $* 4>>test_flac.valgrind.log
+	else
+		flac${EXE} $TOTALLY_SILENT --no-error-on-compression-fail $*
+	fi
+}
+
+run_metaflac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 metaflac $*" >>test_flac.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 metaflac${EXE} $* 4>>test_flac.valgrind.log
+	else
+		metaflac${EXE} $*
+	fi
+}
+
+md5cmp ()
+{
+	n=`( [ -f "$1" ] && [ -f "$2" ] && metaflac${EXE} --show-md5sum --no-filename "$1" "$2" 2>/dev/null || exit 1 ) | uniq | wc -l`
+	[ "$n" != "" ] && [ $n = 1 ]
+}
+
+echo "Checking for --ogg support in flac..."
+if flac${EXE} --ogg $TOTTALY_SILENT --force-raw-format --endian=little --sign=signed --channels=1 --bps=8 --sample-rate=44100 -c $0 1>/dev/null 2>&1 ; then
+	has_ogg=yes;
+	echo "flac --ogg works"
+else
+	has_ogg=no;
+	echo "flac --ogg doesn't work"
+fi
+
+echo "Generating streams..."
+if [ ! -f wacky1.wav ] ; then
+	test_streams || die "ERROR during test_streams"
+fi
+
+############################################################################
+# test that flac doesn't automatically overwrite files unless -f is used
+############################################################################
+
+echo "Try encoding to a file that exists; should fail"
+cp wacky1.wav exist.wav
+touch exist.flac
+if run_flac -0 exist.wav ; then
+	die "ERROR: it should have failed but didn't"
+else
+	echo "OK, it failed as it should"
+fi
+
+echo "Try encoding with -f to a file that exists; should succeed"
+if run_flac -0 --force exist.wav ; then
+	echo "OK, it succeeded as it should"
+else
+	die "ERROR: it should have succeeded but didn't"
+fi
+
+echo "Try decoding to a file that exists; should fail"
+if run_flac -d exist.flac ; then
+	die "ERROR: it should have failed but didn't"
+else
+	echo "OK, it failed as it should"
+fi
+
+echo "Try decoding with -f to a file that exists; should succeed"
+if run_flac -d -f exist.flac ; then
+	echo "OK, it succeeded as it should"
+else
+	die "ERROR: it should have succeeded but didn't"
+fi
+
+rm -f exist.wav exist.flac
+
+############################################################################
+# test fractional block sizes
+############################################################################
+
+test_fractional ()
+{
+	blocksize=$1
+	samples=$2
+	dd if=noise.raw ibs=4 count=$samples of=pbs.raw 2>/dev/null || $dddie
+	echo $ECHO_N "fractional block size test (blocksize=$blocksize samples=$samples) encode... " $ECHO_C
+	run_flac --force --verify --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=$blocksize --no-padding --lax -o pbs.flac pbs.raw || die "ERROR"
+	echo $ECHO_N "decode... " $ECHO_C
+	run_flac --force --decode --force-raw-format --endian=little --sign=signed -o pbs.cmp pbs.flac || die "ERROR"
+	echo $ECHO_N "compare... " $ECHO_C
+	cmp pbs.raw pbs.cmp || die "ERROR: file mismatch"
+	echo "OK"
+	rm -f pbs.raw pbs.flac pbs.cmp
+}
+
+# The special significance of 2048 is it's the # of samples that flac calls
+# FLAC__stream_encoder_process() on.
+#
+# We're trying to make sure the 1-sample overread logic in the stream encoder
+# (used for last-block checking) works; these values probe around common
+# multiples of the flac sample chunk size (2048) and the blocksize.
+for samples in 31 32 33 34 35 2046 2047 2048 2049 2050 ; do
+	test_fractional 33 $samples
+done
+for samples in 254 255 256 257 258 510 511 512 513 514 1022 1023 1024 1025 1026 2046 2047 2048 2049 2050 4094 4095 4096 4097 4098 ; do
+	test_fractional 256 $samples
+done
+for samples in 1022 1023 1024 1025 1026 2046 2047 2048 2049 2050 4094 4095 4096 4097 4098 ; do
+	test_fractional 2048 $samples
+done
+for samples in 1022 1023 1024 1025 1026 2046 2047 2048 2049 2050 4094 4095 4096 4097 4098 4606 4607 4608 4609 4610 8190 8191 8192 8193 8194 16382 16383 16384 16385 16386 ; do
+	test_fractional 4608 $samples
+done
+
+############################################################################
+# basic 'round-trip' tests of various kinds of streams
+############################################################################
+
+rt_test_raw ()
+{
+	f="$1"
+	extra="$2"
+	channels=`echo $f | awk -F- '{print $2}'`
+	bps=`echo $f | awk -F- '{print $3}'`
+	sign=`echo $f | awk -F- '{print $4}'`
+
+	echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C
+	run_flac --force --verify --force-raw-format --endian=little --sign=$sign --sample-rate=44100 --bps=$bps --channels=$channels --no-padding --lax -o rt.flac $extra $f || die "ERROR"
+	echo $ECHO_N "decode... " $ECHO_C
+	run_flac --force --decode --force-raw-format --endian=little --sign=$sign -o rt.raw $extra rt.flac || die "ERROR"
+	echo $ECHO_N "compare... " $ECHO_C
+	cmp $f rt.raw || die "ERROR: file mismatch"
+	echo "OK"
+	rm -f rt.flac rt.raw
+}
+
+rt_test_wav ()
+{
+	f="$1"
+	extra="$2"
+	echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C
+	run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
+	echo $ECHO_N "decode... " $ECHO_C
+	run_flac --force --decode --channel-map=none -o rt.wav $extra rt.flac || die "ERROR"
+	echo $ECHO_N "compare... " $ECHO_C
+	cmp $f rt.wav || die "ERROR: file mismatch"
+	echo "OK"
+	rm -f rt.flac rt.wav
+}
+
+rt_test_w64 ()
+{
+	f="$1"
+	extra="$2"
+	echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C
+	run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
+	echo $ECHO_N "decode... " $ECHO_C
+	run_flac --force --decode --channel-map=none -o rt.w64 $extra rt.flac || die "ERROR"
+	echo $ECHO_N "compare... " $ECHO_C
+	cmp $f rt.w64 || die "ERROR: file mismatch"
+	echo "OK"
+	rm -f rt.flac rt.w64
+}
+
+rt_test_rf64 ()
+{
+	f="$1"
+	extra="$2"
+	echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C
+	run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
+	echo $ECHO_N "decode... " $ECHO_C
+	run_flac --force --decode --channel-map=none -o rt.rf64 $extra rt.flac || die "ERROR"
+	echo $ECHO_N "compare... " $ECHO_C
+	cmp $f rt.rf64 || die "ERROR: file mismatch"
+	echo "OK"
+	rm -f rt.flac rt.rf64
+}
+
+rt_test_aiff ()
+{
+	f="$1"
+	extra="$2"
+	echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C
+	run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
+	echo $ECHO_N "decode... " $ECHO_C
+	run_flac --force --decode --channel-map=none -o rt.aiff $extra rt.flac || die "ERROR"
+	echo $ECHO_N "compare... " $ECHO_C
+	cmp $f rt.aiff || die "ERROR: file mismatch"
+	echo "OK"
+	rm -f rt.flac rt.aiff
+}
+
+# assumes input file is WAVE; does not check the metadata-preserving features of flac-to-flac; that is checked later
+rt_test_flac ()
+{
+	f="$1"
+	extra="$2"
+	echo $ECHO_N "round-trip test ($f->flac->flac->wav) encode... " $ECHO_C
+	run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
+	echo $ECHO_N "re-encode... " $ECHO_C
+	run_flac --force --verify --lax -o rt2.flac rt.flac || die "ERROR"
+	echo $ECHO_N "decode... " $ECHO_C
+	run_flac --force --decode --channel-map=none -o rt.wav $extra rt2.flac || die "ERROR"
+	echo $ECHO_N "compare... " $ECHO_C
+	cmp $f rt.wav || die "ERROR: file mismatch"
+	echo "OK"
+	rm -f rt.wav rt.flac rt2.flac
+}
+
+# assumes input file is WAVE; does not check the metadata-preserving features of flac-to-flac; that is checked later
+rt_test_ogg_flac ()
+{
+	f="$1"
+	extra="$2"
+	echo $ECHO_N "round-trip test ($f->oggflac->oggflac->wav) encode... " $ECHO_C
+	run_flac --force --verify --channel-map=none --no-padding --lax -o rt.oga --ogg $extra $f || die "ERROR"
+	echo $ECHO_N "re-encode... " $ECHO_C
+	run_flac --force --verify --lax -o rt2.oga --ogg rt.oga || die "ERROR"
+	echo $ECHO_N "decode... " $ECHO_C
+	run_flac --force --decode --channel-map=none -o rt.wav $extra rt2.oga || die "ERROR"
+	echo $ECHO_N "compare... " $ECHO_C
+	cmp $f rt.wav || die "ERROR: file mismatch"
+	echo "OK"
+	rm -f rt.wav rt.oga rt2.oga
+}
+
+for f in rt-*.raw ; do
+	rt_test_raw $f
+done
+for f in rt-*.wav ; do
+	rt_test_wav $f
+done
+for f in rt-*.w64 ; do
+	rt_test_w64 $f
+done
+for f in rt-*.rf64 ; do
+	rt_test_rf64 $f
+done
+for f in rt-*.aiff ; do
+	rt_test_aiff $f
+done
+for f in rt-*.wav ; do
+	rt_test_flac $f
+done
+if [ $has_ogg = yes ] ; then
+	for f in rt-*.wav ; do
+		rt_test_ogg_flac $f
+	done
+fi
+
+############################################################################
+# test --skip and --until
+############################################################################
+
+#
+# first make some chopped-up raw files
+#
+echo "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMN" > master.raw
+dd if=master.raw ibs=1 count=50 of=50c.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=10 count=40 of=50c.skip10.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=11 count=39 of=50c.skip11.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=20 count=30 of=50c.skip20.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=30 count=20 of=50c.skip30.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=40 count=10 of=50c.skip40.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=10 of=50c.until10.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=20 of=50c.until20.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=30 of=50c.until30.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=39 of=50c.until39.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=40 of=50c.until40.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=10 count=20 of=50c.skip10.until30.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=10 count=29 of=50c.skip10.until39.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=10 count=30 of=50c.skip10.until40.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=20 count=10 of=50c.skip20.until30.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=20 count=20 of=50c.skip20.until40.raw 2>/dev/null || $dddie
+
+wav_eopt="--force --verify --no-padding --lax"
+wav_dopt="--force --decode"
+
+raw_eopt="$wav_eopt --force-raw-format --endian=big --sign=signed --sample-rate=10 --bps=8 --channels=1"
+raw_dopt="$wav_dopt --force-raw-format --endian=big --sign=signed"
+
+#
+# convert them to WAVE/AIFF/Ogg FLAC files
+#
+convert_to_wav ()
+{
+	run_flac "$2" $1.raw || die "ERROR converting $1.raw to WAVE"
+	run_flac "$3" $1.flac || die "ERROR converting $1.raw to WAVE"
+}
+convert_to_wav 50c "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip10 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip11 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip20 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip30 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip40 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until10 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until20 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until30 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until39 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until40 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip10.until30 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip10.until39 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip10.until40 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip20.until30 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip20.until40 "$raw_eopt" "$wav_dopt"
+
+convert_to_aiff ()
+{
+	run_flac "$2" $1.raw || die "ERROR converting $1.raw to AIFF"
+	run_flac "$3" $1.flac -o $1.aiff || die "ERROR converting $1.raw to AIFF"
+}
+convert_to_aiff 50c "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip10 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip11 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip20 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip30 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip40 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until10 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until20 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until30 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until39 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until40 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip10.until30 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip10.until39 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip10.until40 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip20.until30 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip20.until40 "$raw_eopt" "$wav_dopt"
+
+convert_to_ogg ()
+{
+	run_flac "$wav_eopt" --ogg $1.wav || die "ERROR converting $1.raw to Ogg FLAC"
+}
+if [ $has_ogg = yes ] ; then
+	convert_to_ogg 50c
+	convert_to_ogg 50c.skip10
+	convert_to_ogg 50c.skip11
+	convert_to_ogg 50c.skip20
+	convert_to_ogg 50c.skip30
+	convert_to_ogg 50c.skip40
+	convert_to_ogg 50c.until10
+	convert_to_ogg 50c.until20
+	convert_to_ogg 50c.until30
+	convert_to_ogg 50c.until39
+	convert_to_ogg 50c.until40
+	convert_to_ogg 50c.skip10.until30
+	convert_to_ogg 50c.skip10.until39
+	convert_to_ogg 50c.skip10.until40
+	convert_to_ogg 50c.skip20.until30
+	convert_to_ogg 50c.skip20.until40
+fi
+
+test_skip_until ()
+{
+	in_fmt=$1
+	out_fmt=$2
+
+	[ "$in_fmt" = wav ] || [ "$in_fmt" = aiff ] || [ "$in_fmt" = raw ] || [ "$in_fmt" = flac ] || [ "$in_fmt" = ogg ] || die "ERROR: internal error, bad 'in' format '$in_fmt'"
+
+	[ "$out_fmt" = flac ] || [ "$out_fmt" = ogg ] || die "ERROR: internal error, bad 'out' format '$out_fmt'"
+
+	if [ $in_fmt = raw ] ; then
+		eopt="$raw_eopt"
+		dopt="$raw_dopt"
+	else
+		eopt="$wav_eopt"
+		dopt="$wav_dopt"
+	fi
+
+	if ( [ $in_fmt = flac ] || [ $in_fmt = ogg ] ) && ( [ $out_fmt = flac ] || [ $out_fmt = ogg ] ) ; then
+		CMP=md5cmp
+	else
+		CMP=cmp
+	fi
+
+	if [ $out_fmt = ogg ] ; then
+		eopt="--ogg $eopt"
+	fi
+
+	#
+	# test --skip when encoding
+	#
+
+	desc="($in_fmt<->$out_fmt)"
+
+	echo $ECHO_N "testing --skip=# (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 -o z50c.skip10.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.$in_fmt z50c.skip10.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.$in_fmt z50c.skip10.$in_fmt || die "ERROR: file mismatch for --skip=10 (encode) $desc"
+	rm -f z50c.skip10.$out_fmt z50c.skip10.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=mm:ss (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=0:01 -o z50c.skip0_01.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip0_01.$in_fmt z50c.skip0_01.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.$in_fmt z50c.skip0_01.$in_fmt || die "ERROR: file mismatch for --skip=0:01 (encode) $desc"
+	rm -f z50c.skip0_01.$out_fmt z50c.skip0_01.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=mm:ss.sss (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=0:01.1001 -o z50c.skip0_01.1001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip0_01.1001.$in_fmt z50c.skip0_01.1001.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip11.$in_fmt z50c.skip0_01.1001.$in_fmt || die "ERROR: file mismatch for --skip=0:01.1001 (encode) $desc"
+	rm -f z50c.skip0_01.1001.$out_fmt z50c.skip0_01.1001.$in_fmt
+	echo OK
+
+	#
+	# test --skip when decoding
+	#
+
+	if [ $in_fmt != $out_fmt ] ; then run_flac $eopt -o z50c.$out_fmt 50c.$in_fmt ; else cp -f 50c.$in_fmt z50c.$out_fmt ; fi || die "ERROR generating FLAC file $desc"
+
+	echo $ECHO_N "testing --skip=# (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=10 -o z50c.skip10.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.$in_fmt z50c.skip10.$in_fmt || die "ERROR: file mismatch for --skip=10 (decode) $desc"
+	rm -f z50c.skip10.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=mm:ss (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=0:01 -o z50c.skip0_01.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.$in_fmt z50c.skip0_01.$in_fmt || die "ERROR: file mismatch for --skip=0:01 (decode) $desc"
+	rm -f z50c.skip0_01.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=mm:ss.sss (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=0:01.1001 -o z50c.skip0_01.1001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip11.$in_fmt z50c.skip0_01.1001.$in_fmt || die "ERROR: file mismatch for --skip=0:01.1001 (decode) $desc"
+	rm -f z50c.skip0_01.1001.$in_fmt
+	echo OK
+
+	rm -f z50c.$out_fmt
+
+	#
+	# test --until when encoding
+	#
+
+	echo $ECHO_N "testing --until=# (encode) $desc... " $ECHO_C
+	run_flac $eopt --until=40 -o z50c.until40.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until40.$in_fmt z50c.until40.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.until40.$in_fmt || die "ERROR: file mismatch for --until=40 (encode) $desc"
+	rm -f z50c.until40.$out_fmt z50c.until40.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=mm:ss (encode) $desc... " $ECHO_C
+	run_flac $eopt --until=0:04 -o z50c.until0_04.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until0_04.$in_fmt z50c.until0_04.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.until0_04.$in_fmt || die "ERROR: file mismatch for --until=0:04 (encode) $desc"
+	rm -f z50c.until0_04.$out_fmt z50c.until0_04.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=mm:ss.sss (encode) $desc... " $ECHO_C
+	run_flac $eopt --until=0:03.9001 -o z50c.until0_03.9001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until0_03.9001.$in_fmt z50c.until0_03.9001.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until39.$in_fmt z50c.until0_03.9001.$in_fmt || die "ERROR: file mismatch for --until=0:03.9001 (encode) $desc"
+	rm -f z50c.until0_03.9001.$out_fmt z50c.until0_03.9001.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=-# (encode) $desc... " $ECHO_C
+	run_flac $eopt --until=-10 -o z50c.until-10.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until-10.$in_fmt z50c.until-10.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.until-10.$in_fmt || die "ERROR: file mismatch for --until=-10 (encode) $desc"
+	rm -f z50c.until-10.$out_fmt z50c.until-10.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=-mm:ss (encode) $desc... " $ECHO_C
+	run_flac $eopt --until=-0:01 -o z50c.until-0_01.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until-0_01.$in_fmt z50c.until-0_01.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.until-0_01.$in_fmt || die "ERROR: file mismatch for --until=-0:01 (encode) $desc"
+	rm -f z50c.until-0_01.$out_fmt z50c.until-0_01.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=-mm:ss.sss (encode) $desc... " $ECHO_C
+	run_flac $eopt --until=-0:01.1001 -o z50c.until-0_01.1001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until-0_01.1001.$in_fmt z50c.until-0_01.1001.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until39.$in_fmt z50c.until-0_01.1001.$in_fmt || die "ERROR: file mismatch for --until=-0:01.1001 (encode) $desc"
+	rm -f z50c.until-0_01.1001.$out_fmt z50c.until-0_01.1001.$in_fmt
+	echo OK
+
+	#
+	# test --until when decoding
+	#
+
+	if [ $in_fmt != $out_fmt ] ; then run_flac $eopt -o z50c.$out_fmt 50c.$in_fmt ; else cp -f 50c.$in_fmt z50c.$out_fmt ; fi || die "ERROR generating FLAC file $desc"
+
+	echo $ECHO_N "testing --until=# (decode) $desc... " $ECHO_C
+	run_flac $dopt --until=40 -o z50c.until40.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.until40.$in_fmt || die "ERROR: file mismatch for --until=40 (decode) $desc"
+	rm -f z50c.until40.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=mm:ss (decode) $desc... " $ECHO_C
+	run_flac $dopt --until=0:04 -o z50c.until0_04.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.until0_04.$in_fmt || die "ERROR: file mismatch for --until=0:04 (decode) $desc"
+	rm -f z50c.until0_04.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=mm:ss.sss (decode) $desc... " $ECHO_C
+	run_flac $dopt --until=0:03.9001 -o z50c.until0_03.9001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until39.$in_fmt z50c.until0_03.9001.$in_fmt || die "ERROR: file mismatch for --until=0:03.9001 (decode) $desc"
+	rm -f z50c.until0_03.9001.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=-# (decode) $desc... " $ECHO_C
+	run_flac $dopt --until=-10 -o z50c.until-10.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.until-10.$in_fmt || die "ERROR: file mismatch for --until=-10 (decode) $desc"
+	rm -f z50c.until-10.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=-mm:ss (decode) $desc... " $ECHO_C
+	run_flac $dopt --until=-0:01 -o z50c.until-0_01.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.until-0_01.$in_fmt || die "ERROR: file mismatch for --until=-0:01 (decode) $desc"
+	rm -f z50c.until-0_01.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --until=-mm:ss.sss (decode) $desc... " $ECHO_C
+	run_flac $dopt --until=-0:01.1001 -o z50c.until-0_01.1001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until39.$in_fmt z50c.until-0_01.1001.$in_fmt || die "ERROR: file mismatch for --until=-0:01.1001 (decode) $desc"
+	rm -f z50c.until-0_01.1001.$in_fmt
+	echo OK
+
+	rm -f z50c.$out_fmt
+
+	#
+	# test --skip and --until when encoding
+	#
+
+	echo $ECHO_N "testing --skip=10 --until=# (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=40 -o z50c.skip10.until40.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until40.$in_fmt z50c.skip10.until40.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until40.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=40 (encode) $desc"
+	rm -f z50c.skip10.until40.$out_fmt z50c.skip10.until40.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=mm:ss (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=0:04 -o z50c.skip10.until0_04.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until0_04.$in_fmt z50c.skip10.until0_04.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until0_04.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=0:04 (encode) $desc"
+	rm -f z50c.skip10.until0_04.$out_fmt z50c.skip10.until0_04.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=mm:ss.sss (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=0:03.9001 -o z50c.skip10.until0_03.9001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until0_03.9001.$in_fmt z50c.skip10.until0_03.9001.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until39.$in_fmt z50c.skip10.until0_03.9001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=0:03.9001 (encode) $desc"
+	rm -f z50c.skip10.until0_03.9001.$out_fmt z50c.skip10.until0_03.9001.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=+# (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=+30 -o z50c.skip10.until+30.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until+30.$in_fmt z50c.skip10.until+30.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until+30.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=+30 (encode) $desc"
+	rm -f z50c.skip10.until+30.$out_fmt z50c.skip10.until+30.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=+mm:ss (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=+0:03 -o z50c.skip10.until+0_03.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until+0_03.$in_fmt z50c.skip10.until+0_03.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until+0_03.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=+0:03 (encode) $desc"
+	rm -f z50c.skip10.until+0_03.$out_fmt z50c.skip10.until+0_03.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=+mm:ss.sss (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=+0:02.9001 -o z50c.skip10.until+0_02.9001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until+0_02.9001.$in_fmt z50c.skip10.until+0_02.9001.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until39.$in_fmt z50c.skip10.until+0_02.9001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=+0:02.9001 (encode) $desc"
+	rm -f z50c.skip10.until+0_02.9001.$out_fmt z50c.skip10.until+0_02.9001.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=-# (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=-10 -o z50c.skip10.until-10.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until-10.$in_fmt z50c.skip10.until-10.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until-10.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-10 (encode) $desc"
+	rm -f z50c.skip10.until-10.$out_fmt z50c.skip10.until-10.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=-mm:ss (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=-0:01 -o z50c.skip10.until-0_01.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until-0_01.$in_fmt z50c.skip10.until-0_01.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until-0_01.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-0:01 (encode) $desc"
+	rm -f z50c.skip10.until-0_01.$out_fmt z50c.skip10.until-0_01.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=-mm:ss.sss (encode) $desc... " $ECHO_C
+	run_flac $eopt --skip=10 --until=-0:01.1001 -o z50c.skip10.until-0_01.1001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+	[ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until-0_01.1001.$in_fmt z50c.skip10.until-0_01.1001.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until39.$in_fmt z50c.skip10.until-0_01.1001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-0:01.1001 (encode) $desc"
+	rm -f z50c.skip10.until-0_01.1001.$out_fmt z50c.skip10.until-0_01.1001.$in_fmt
+	echo OK
+
+	#
+	# test --skip and --until when decoding
+	#
+
+	if [ $in_fmt != $out_fmt ] ; then run_flac $eopt -o z50c.$out_fmt 50c.$in_fmt ; else cp -f 50c.$in_fmt z50c.$out_fmt ; fi || die "ERROR generating FLAC file $desc"
+
+
+	echo $ECHO_N "testing --skip=10 --until=# (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=10 --until=40 -o z50c.skip10.until40.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until40.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=40 (decode) $desc"
+	rm -f z50c.skip10.until40.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=mm:ss (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=10 --until=0:04 -o z50c.skip10.until0_04.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until0_04.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=0:04 (decode) $desc"
+	rm -f z50c.skip10.until0_04.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=mm:ss.sss (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=10 --until=0:03.9001 -o z50c.skip10.until0_03.9001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until39.$in_fmt z50c.skip10.until0_03.9001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=0:03.9001 (decode) $desc"
+	rm -f z50c.skip10.until0_03.9001.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=-# (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=10 --until=-10 -o z50c.skip10.until-10.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until-10.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-10 (decode) $desc"
+	rm -f z50c.skip10.until-10.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=-mm:ss (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=10 --until=-0:01 -o z50c.skip10.until-0_01.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.skip10.until-0_01.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-0:01 (decode) $desc"
+	rm -f z50c.skip10.until-0_01.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --skip=10 --until=-mm:ss.sss (decode) $desc... " $ECHO_C
+	run_flac $dopt --skip=10 --until=-0:01.1001 -o z50c.skip10.until-0_01.1001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until39.$in_fmt z50c.skip10.until-0_01.1001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-0:01.1001 (decode) $desc"
+	rm -f z50c.skip10.until-0_01.1001.$in_fmt
+	echo OK
+
+	rm -f z50c.$out_fmt
+}
+
+test_skip_until raw flac
+test_skip_until wav flac
+test_skip_until aiff flac
+test_skip_until flac flac
+#@@@if [ $has_ogg = yes ] ; then
+#@@@	#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+#@@@	test_skip_until ogg flac
+#@@@fi
+
+if [ $has_ogg = yes ] ; then
+	test_skip_until raw ogg
+	test_skip_until wav ogg
+	test_skip_until aiff ogg
+	#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+	#@@@test_skip_until flac ogg
+	#@@@test_skip_until ogg ogg
+fi
+
+echo "testing seek extremes:"
+
+run_flac --verify --force --no-padding --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=576 noise.raw || die "ERROR generating FLAC file"
+
+if [ $is_win = no ] ; then
+	total_noise_cdda_samples=`run_metaflac --show-total-samples noise.flac`
+	[ $? = 0 ] || die "ERROR getting total sample count from noise.flac"
+else
+	# some flavors of cygwin don't seem to treat the \x0d as a word
+	# separator, so we hard code it.  we'll just have to fix it later
+	# if we change the way noise.flac is made.
+	total_noise_cdda_samples=393216
+fi
+
+echo $ECHO_N "testing --skip=0... " $ECHO_C
+run_flac $wav_dopt --skip=0 -o z.wav noise.flac || die "ERROR decoding FLAC file noise.flac"
+echo OK
+
+for delta in 2 1 ; do
+	n=`expr $total_noise_cdda_samples - $delta`
+	echo $ECHO_N "testing --skip=$n... " $ECHO_C
+	run_flac $wav_dopt --skip=$n -o z.wav noise.flac || die "ERROR decoding FLAC file noise.flac"
+	echo OK
+done
+
+rm noise.flac z.wav
+
+############################################################################
+# test --input-size
+############################################################################
+
+#@@@ cat will not work on old cygwin, need to fix
+if [ $is_win = no ] ; then
+	echo $ECHO_N "testing --input-size=50 --skip=10... " $ECHO_C
+	cat 50c.raw | run_flac $raw_eopt --input-size=50 --skip=10 -o z50c.skip10.flac - || die "ERROR generating FLAC file"
+	run_flac $raw_dopt -o z50c.skip10.raw z50c.skip10.flac || die "ERROR decoding FLAC file"
+	cmp 50c.skip10.raw z50c.skip10.raw || die "ERROR: file mismatch for --input-size=50 --skip=10"
+	rm -f z50c.skip10.raw z50c.skip10.flac
+	echo OK
+fi
+
+############################################################################
+# test --output-prefix
+############################################################################
+
+in_dir=./tmp_in
+out_dir=./tmp_out
+mkdir $in_dir $out_dir || die "ERROR failed to create temp directories"
+
+cp 50c.raw 50c.flac $in_dir
+
+#
+# test --output-prefix when encoding
+#
+
+echo $ECHO_N "testing --output-prefix=$out_dir/ (encode)... " $ECHO_C
+run_flac $raw_eopt --output-prefix=$out_dir/ $in_dir/50c.raw || die "ERROR generating FLAC file in $out_dir (encode)"
+[ -f $out_dir/50c.flac ] || die "ERROR FLAC file not in $out_dir (encode)"
+run_flac $raw_dopt $out_dir/50c.flac || die "ERROR decoding FLAC file (encode)"
+[ -f $out_dir/50c.raw ] || die "ERROR RAW file not in $out_dir (encode)"
+cmp 50c.raw $out_dir/50c.raw || die "ERROR: file mismatch for --output-prefix=$out_dir (encode)"
+rm -f $out_dir/50c.flac $out_dir/50c.raw
+echo OK
+
+#
+# test --ouput-prefix when decoding
+#
+
+echo $ECHO_N "testing --output-prefix=$out_dir/ (decode)... " $ECHO_C
+run_flac $raw_dopt --output-prefix=$out_dir/ $in_dir/50c.flac || die "ERROR deocding FLAC file in $out_dir (decode)"
+[ -f $out_dir/50c.raw ] || die "ERROR RAW file not in $out_dir (decode)"
+run_flac $raw_eopt $out_dir/50c.raw || die "ERROR generating FLAC file (decode)"
+[ -f $out_dir/50c.flac ] || die "ERROR FLAC file not in $out_dir (decode)"
+cmp 50c.flac $out_dir/50c.flac || die "ERROR: file mismatch for --output-prefix=$out_dir (decode)"
+rm -f $out_dir/50c.flac $out_dir/50c.raw
+echo OK
+
+rm -rf $in_dir $out_dir
+
+############################################################################
+# test --cue
+############################################################################
+
+#
+# create the cue sheet
+#
+cuesheet=cuetest.cue
+cat > $cuesheet << EOF
+CATALOG 1234567890123
+FILE "blah" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 0
+    INDEX 02 10
+    INDEX 03 20
+  TRACK 02 AUDIO
+    INDEX 01 30
+  TRACK 04 AUDIO
+    INDEX 01 40
+EOF
+
+test_cue ()
+{
+	in_fmt=$1
+	out_fmt=$2
+
+	[ "$in_fmt" = wav ] || [ "$in_fmt" = aiff ] || [ "$in_fmt" = raw ] || [ "$in_fmt" = flac ] || [ "$in_fmt" = ogg ] || die "ERROR: internal error, bad 'in' format '$in_fmt'"
+
+	[ "$out_fmt" = flac ] || [ "$out_fmt" = ogg ] || die "ERROR: internal error, bad 'out' format '$out_fmt'"
+
+	if [ $in_fmt = raw ] ; then
+		eopt="$raw_eopt"
+		dopt="$raw_dopt"
+	else
+		eopt="$wav_eopt"
+		dopt="$wav_dopt"
+	fi
+
+	if ( [ $in_fmt = flac ] || [ $in_fmt = ogg ] ) && ( [ $out_fmt = flac ] || [ $out_fmt = ogg ] ) ; then
+		CMP=md5cmp
+	else
+		CMP=cmp
+	fi
+
+	if [ $out_fmt = ogg ] ; then
+		eopt="--ogg $eopt"
+	fi
+
+	desc="($in_fmt<->$out_fmt)"
+
+	#
+	# for this we need just need just one FLAC file; --cue only works while decoding
+	#
+	run_flac $eopt --cuesheet=$cuesheet -o z50c.cue.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+
+	# To make it easy to translate from cue point to sample numbers, the
+	# file has a sample rate of 10 Hz and a cuesheet like so:
+	#
+	# TRACK 01, INDEX 01 : 0:00.00 -> sample 0
+	# TRACK 01, INDEX 02 : 0:01.00 -> sample 10
+	# TRACK 01, INDEX 03 : 0:02.00 -> sample 20
+	# TRACK 02, INDEX 01 : 0:03.00 -> sample 30
+	# TRACK 04, INDEX 01 : 0:04.00 -> sample 40
+	#
+	echo $ECHO_N "testing --cue=- $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=- $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.0 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.0 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.0- $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.0- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.0- $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.1 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.1 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.1 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.1- $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.1- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.1- $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.2 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.2 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.2 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.2- $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.2- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.2- $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.4 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.4 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip20.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.4 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.4- $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.4- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip20.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.4- $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=-5.0 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=-5.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=-5.0 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=-4.1 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=-4.1 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=-4.1 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=-3.1 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=-3.1 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until40.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=-3.1 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=-1.4 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=-1.4 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.until30.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=-1.4 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.0-5.0 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.0-5.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.0-5.0 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.1-5.0 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.1-5.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.1-5.0 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.2-4.1 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.2-4.1 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip10.until40.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.2-4.1 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	echo $ECHO_N "testing --cue=1.4-2.0 $desc... " $ECHO_C
+	run_flac $dopt -o z50c.cued.$in_fmt --cue=1.4-2.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+	$CMP 50c.skip20.until30.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.4-2.0 $desc"
+	rm -f z50c.cued.$in_fmt
+	echo OK
+
+	rm -f z50c.cue.$out_fmt
+}
+
+test_cue raw flac
+test_cue wav flac
+test_cue aiff flac
+test_cue flac flac
+#@@@if [ $has_ogg = yes ] ; then
+#@@@	#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+#@@@	test_cue ogg flac
+#@@@fi
+
+if [ $has_ogg = yes ] ; then
+	test_cue raw ogg
+	test_cue wav ogg
+	test_cue aiff ogg
+	#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+	#@@@test_cue flac ogg
+	#@@@test_cue ogg ogg
+fi
+
+############################################################################
+# test 'fixup' code that happens when a FLAC file with total_samples == 0
+# in the STREAMINFO block is converted to WAVE or AIFF, requiring the
+# decoder go back and fix up the chunk headers
+############################################################################
+
+echo $ECHO_N "WAVE fixup test... " $ECHO_C
+
+echo $ECHO_N "prepare... " $ECHO_C
+convert_to_wav noise "$raw_eopt" "$wav_dopt" || die "ERROR creating reference WAVE"
+
+echo $ECHO_N "encode... " $ECHO_C
+# the pipe from 'cat' to 'flac' does not work on cygwin because of the EOF/
+# binary-mode stdin problem, so we use an undocumented option to metaflac to
+# set the total sample count to 0
+if [ $is_win = yes ] ; then
+	run_flac $raw_eopt noise.raw -o fixup.flac || die "ERROR generating FLAC file"
+	run_metaflac --set-total-samples=0 fixup.flac 2> /dev/null
+else
+	cat noise.raw | run_flac $raw_eopt - -c > fixup.flac || die "ERROR generating FLAC file"
+fi
+
+echo $ECHO_N "decode... " $ECHO_C
+run_flac $wav_dopt fixup.flac -o fixup.wav || die "ERROR decoding FLAC file"
+
+echo $ECHO_N "compare... " $ECHO_C
+cmp noise.wav fixup.wav || die "ERROR: file mismatch"
+
+echo OK
+rm -f noise.wav fixup.wav fixup.flac
+
+echo $ECHO_N "AIFF fixup test... " $ECHO_C
+
+echo $ECHO_N "prepare... " $ECHO_C
+convert_to_aiff noise "$raw_eopt" "$wav_dopt" || die "ERROR creating reference AIFF"
+
+echo $ECHO_N "encode... " $ECHO_C
+# the pipe from 'cat' to 'flac' does not work on cygwin because of the EOF/
+# binary-mode stdin problem, so we use an undocumented option to metaflac to
+# set the total sample count to 0
+if [ $is_win = yes ] ; then
+	run_flac $raw_eopt noise.raw -o fixup.flac || die "ERROR generating FLAC file"
+	run_metaflac --set-total-samples=0 fixup.flac 2> /dev/null
+else
+	cat noise.raw | run_flac $raw_eopt - -c > fixup.flac || die "ERROR generating FLAC file"
+fi
+
+echo $ECHO_N "decode... " $ECHO_C
+run_flac $wav_dopt fixup.flac -o fixup.aiff || die "ERROR decoding FLAC file"
+
+echo $ECHO_N "compare... " $ECHO_C
+cmp noise.aiff fixup.aiff || die "ERROR: file mismatch"
+
+echo OK
+rm -f noise.aiff fixup.aiff fixup.flac
+
+
+############################################################################
+# multi-file tests
+############################################################################
+
+echo "Generating multiple input files from noise..."
+multifile_format_decode="--endian=big --sign=signed"
+multifile_format_encode="$multifile_format_decode --sample-rate=44100 --bps=16 --channels=2 --no-padding"
+short_noise_cdda_samples=`expr $total_noise_cdda_samples / 8`
+run_flac --verify --force --force-raw-format $multifile_format_encode --until=$short_noise_cdda_samples -o shortnoise.flac noise.raw || die "ERROR generating FLAC file"
+run_flac --decode --force shortnoise.flac -o shortnoise.raw --force-raw-format $multifile_format_decode || die "ERROR generating RAW file"
+run_flac --decode --force shortnoise.flac || die "ERROR generating WAVE file"
+run_flac --decode --force shortnoise.flac -o shortnoise.aiff || die "ERROR generating AIFF file"
+cp shortnoise.flac file0.flac
+cp shortnoise.flac file1.flac
+cp shortnoise.flac file2.flac
+rm -f shortnoise.flac
+cp shortnoise.wav file0.wav
+cp shortnoise.wav file1.wav
+cp shortnoise.wav file2.wav
+rm -f shortnoise.wav
+cp shortnoise.aiff file0.aiff
+cp shortnoise.aiff file1.aiff
+cp shortnoise.aiff file2.aiff
+rm -f shortnoise.aiff
+cp shortnoise.raw file0.raw
+cp shortnoise.raw file1.raw
+cp shortnoise.raw file2.raw
+rm -f shortnoise.raw
+# create authoritative sector-aligned files for comparison
+file0_samples=`expr \( $short_noise_cdda_samples / 588 \) \* 588`
+file0_remainder=`expr $short_noise_cdda_samples - $file0_samples`
+file1_samples=`expr \( \( $file0_remainder + $short_noise_cdda_samples \) / 588 \) \* 588`
+file1_remainder=`expr $file0_remainder + $short_noise_cdda_samples - $file1_samples`
+file1_samples=`expr $file1_samples - $file0_remainder`
+file2_samples=`expr \( \( $file1_remainder + $short_noise_cdda_samples \) / 588 \) \* 588`
+file2_remainder=`expr $file1_remainder + $short_noise_cdda_samples - $file2_samples`
+file2_samples=`expr $file2_samples - $file1_remainder`
+if [ $file2_remainder != '0' ] ; then
+	file2_samples=`expr $file2_samples + $file2_remainder`
+	file2_remainder=`expr 588 - $file2_remainder`
+fi
+
+dd if=file0.raw ibs=4 count=$file0_samples of=file0s.raw 2>/dev/null || $dddie
+dd if=file0.raw ibs=4 count=$file0_remainder of=file1s.raw skip=$file0_samples 2>/dev/null || $dddie
+dd if=file1.raw ibs=4 count=$file1_samples of=z.raw 2>/dev/null || $dddie
+cat z.raw >> file1s.raw || die "ERROR: cat-ing sector-aligned files"
+dd if=file1.raw ibs=4 count=$file1_remainder of=file2s.raw skip=$file1_samples 2>/dev/null || $dddie
+dd if=file2.raw ibs=4 count=$file2_samples of=z.raw 2>/dev/null || $dddie
+cat z.raw >> file2s.raw || die "ERROR: cat-ing sector-aligned files"
+dd if=/dev/zero ibs=4 count=$file2_remainder of=z.raw 2>/dev/null || $dddie
+cat z.raw >> file2s.raw || die "ERROR: cat-ing sector-aligned files"
+rm -f z.raw
+
+convert_to_wav file0s "$multifile_format_encode --force --force-raw-format" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned WAVE"
+convert_to_wav file1s "$multifile_format_encode --force --force-raw-format" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned WAVE"
+convert_to_wav file2s "$multifile_format_encode --force --force-raw-format" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned WAVE"
+
+convert_to_aiff file0s "$multifile_format_encode --force --force-raw-format" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned AIFF"
+convert_to_aiff file1s "$multifile_format_encode --force --force-raw-format" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned AIFF"
+convert_to_aiff file2s "$multifile_format_encode --force --force-raw-format" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned AIFF"
+
+test_multifile ()
+{
+	input_type=$1
+	streamtype=$2
+	sector_align=$3
+	encode_options="$4"
+
+	extra_encode_options=""
+	extra_decode_options=""
+	if [ $input_type = "raw" ] ; then
+		extra_encode_options="--force-raw-format $multifile_format_encode"
+		extra_decode_options="--force-raw-format $multifile_format_decode"
+	else
+		if [ $input_type = "aiff" ] ; then
+			extra_decode_options="--force-aiff-format"
+		fi
+	fi
+
+	if [ $streamtype = ogg ] ; then
+		suffix=oga
+		encode_options="$encode_options --ogg"
+	else
+		suffix=flac
+	fi
+
+	if [ $sector_align = sector_align ] ; then
+		encode_options="$encode_options --sector-align"
+	fi
+
+	if [ $input_type = flac ] || [ $input_type = ogg ] ; then
+		CMP=md5cmp
+	else
+		CMP=cmp
+	fi
+
+	for n in 0 1 2 ; do
+		cp file$n.$input_type file${n}x.$input_type
+	done
+	run_flac --force $encode_options $extra_encode_options file0x.$input_type file1x.$input_type file2x.$input_type || die "ERROR"
+	run_flac --force --decode $extra_decode_options file0x.$suffix file1x.$suffix file2x.$suffix || die "ERROR"
+	if [ $sector_align != sector_align ] ; then
+		for n in 0 1 2 ; do
+			$CMP file$n.$input_type file${n}x.$input_type || die "ERROR: file mismatch on file #$n"
+		done
+	else
+		for n in 0 1 2 ; do
+			$CMP file${n}s.$input_type file${n}x.$input_type || die "ERROR: file mismatch on file #$n"
+		done
+	fi
+	for n in 0 1 2 ; do
+		rm -f file${n}x.$suffix file${n}x.$input_type
+	done
+}
+
+input_types="raw wav aiff flac"
+#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+#@@@if [ $has_ogg = yes ] ; then
+#@@@	input_types="$input_types ogg"
+#@@@fi
+for input_type in $input_types ; do
+	echo "Testing multiple $input_type files without verify..."
+	test_multifile $input_type flac no_sector_align ""
+
+	echo "Testing multiple $input_type files with verify..."
+	test_multifile $input_type flac no_sector_align "--verify"
+
+	if [ $input_type != flac ] && [ $input_type != ogg ] ; then # --sector-align not supported for FLAC input
+		echo "Testing multiple $input_type files with --sector-align, without verify..."
+		test_multifile $input_type flac sector_align ""
+
+		echo "Testing multiple $input_type files with --sector-align, with verify..."
+		test_multifile $input_type flac sector_align "--verify"
+	fi
+
+	if [ $has_ogg = yes ] ; then
+		echo "Testing multiple $input_type files with --ogg, without verify..."
+		test_multifile $input_type ogg no_sector_align ""
+
+		echo "Testing multiple $input_type files with --ogg, with verify..."
+		test_multifile $input_type ogg no_sector_align "--verify"
+
+		if [ $input_type != flac ] ; then # --sector-align not supported for FLAC input
+			echo "Testing multiple $input_type files with --ogg and --sector-align, without verify..."
+			test_multifile $input_type ogg sector_align ""
+
+			echo "Testing multiple $input_type files with --ogg and --sector-align, with verify..."
+			test_multifile $input_type ogg sector_align "--verify"
+		fi
+
+		echo "Testing multiple $input_type files with --ogg and --serial-number, with verify..."
+		test_multifile $input_type ogg no_sector_align "--serial-number=321 --verify"
+	fi
+done
+
+
+############################################################################
+# test --keep-foreign-metadata
+############################################################################
+
+echo "Testing --keep-foreign-metadata..."
+
+rt_test_wav wacky1.wav '--keep-foreign-metadata'
+rt_test_wav wacky2.wav '--keep-foreign-metadata'
+rt_test_w64 wacky1.w64 '--keep-foreign-metadata'
+rt_test_w64 wacky2.w64 '--keep-foreign-metadata'
+rt_test_rf64 wacky1.rf64 '--keep-foreign-metadata'
+rt_test_rf64 wacky2.rf64 '--keep-foreign-metadata'
+
+
+############################################################################
+# test the metadata-handling properties of flac-to-flac encoding
+############################################################################
+
+echo "Testing the metadata-handling properties of flac-to-flac encoding..."
+
+testdatadir=${top_srcdir}/test/flac-to-flac-metadata-test-files
+
+filter ()
+{
+	# minor danger, changing vendor strings might change the length of the
+	# VORBIS_COMMENT block, but if we add "^  length: " to the patterns,
+	# we lose info about PADDING size that we need
+	grep -Ev '^  vendor string: |^  m..imum .....size: ' | sed -e 's/, stream_offset.*//'
+}
+flac2flac ()
+{
+	file="$testdatadir/$1"
+	case="$testdatadir/$2"
+	args="$3"
+	expect="$case-expect.meta"
+	echo $ECHO_N "$2... " $ECHO_C
+	# The 'make distcheck' target needs this.
+	chmod u+w $file
+	run_flac -f -o out.flac $args $file || die "ERROR encoding FLAC file"
+	run_metaflac --list out.flac | filter > out1.meta || die "ERROR listing metadata of output FLAC file"
+    # Ignore lengths which can be affected by the version string.
+    sed "s/length:.*/length: XXX/" out1.meta > out.meta
+	diff -q -w $expect out.meta 2>/dev/null || die "ERROR: metadata does not match expected $expect"
+	echo OK
+}
+
+#filter=', stream_offset.*|^  vendor string: |^  length: |^  m..imum .....size: '
+
+# case 00a: no alterations on a file with all metadata types, keep all metadata, in same order
+flac2flac input-SCVAUP.flac case00a ""
+# case 01a: on file with multiple PADDING blocks, they should be aggregated into one at the end
+flac2flac input-SCVPAP.flac case01a ""
+# case 01b: on file with multiple PADDING blocks and --no-padding specified, they should all be deleted
+flac2flac input-SCVPAP.flac case01b "--no-padding"
+# case 01c: on file with multiple PADDING blocks and -P specified, they should all be overwritten with -P value
+flac2flac input-SCVPAP.flac case01c "-P 1234"
+# case 01d: on file with no PADDING blocks, use -P setting
+flac2flac input-SCVA.flac case01d "-P 1234"
+# case 01e: on file with no PADDING blocks and no -P given, use default padding
+flac2flac input-SCVA.flac case01e ""
+# case 02a: on file with no VORBIS_COMMENT block, add new VORBIS_COMMENT
+flac2flac input-SCPAP.flac case02a ""
+# case 02b: on file with no VORBIS_COMMENT block and --tag, add new VORBIS_COMMENT with tags
+flac2flac input-SCPAP.flac case02b "--tag=artist=0"
+# case 02c: on file with VORBIS_COMMENT block and --tag, replace existing VORBIS_COMMENT with new tags
+flac2flac input-SCVAUP.flac case02c "--tag=artist=0"
+# case 03a: on file with no CUESHEET block and --cuesheet specified, add it
+flac2flac input-SVAUP.flac case03a "--cuesheet=$testdatadir/input0.cue"
+# case 03b: on file with CUESHEET block and --cuesheet specified, overwrite existing CUESHEET
+flac2flac input-SCVAUP.flac case03b "--cuesheet=$testdatadir/input0.cue"
+# case 03c: on file with CUESHEET block and size-changing option specified, drop existing CUESHEET
+flac2flac input-SCVAUP.flac case03c "--skip=1"
+# case 04a: on file with no SEEKTABLE block and --no-seektable specified, no SEEKTABLE
+flac2flac input-VA.flac case04a "--no-padding --no-seektable"
+# case 04b: on file with no SEEKTABLE block and -S specified, new SEEKTABLE
+flac2flac input-VA.flac case04b "--no-padding -S 5x"
+# case 04c: on file with no SEEKTABLE block and no seektable options specified, new SEEKTABLE with default points
+flac2flac input-VA.flac case04c "--no-padding"
+# case 04d: on file with SEEKTABLE block and --no-seektable specified, drop existing SEEKTABLE
+flac2flac input-SCVA.flac case04d "--no-padding --no-seektable"
+# case 04e: on file with SEEKTABLE block and -S specified, overwrite existing SEEKTABLE
+flac2flac input-SCVA.flac case04e "--no-padding -S 5x"
+# case 04f: on file with SEEKTABLE block and size-changing option specified, drop existing SEEKTABLE, new SEEKTABLE with default points
+#(already covered by case03c)
+
+rm -f out.flac out.meta out1.meta
+
+#@@@ when metaflac handles ogg flac, duplicate flac2flac tests here
+
+cd ..
diff --git a/test/test_grabbag.sh b/test/test_grabbag.sh
new file mode 100755
index 0000000..3af2741
--- /dev/null
+++ b/test/test_grabbag.sh
@@ -0,0 +1,128 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+PATH=../src/test_grabbag/cuesheet:$PATH
+PATH=../src/test_grabbag/picture:$PATH
+PATH=../objs/$BUILD/bin:$PATH
+
+test_cuesheet -h 1>/dev/null 2>/dev/null || die "ERROR can't find test_cuesheet executable"
+test_picture -h 1>/dev/null 2>/dev/null || die "ERROR can't find test_picture executable"
+
+run_test_cuesheet ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 test_cuesheet $*" >>test_grabbag.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 test_cuesheet${EXE} $* 4>>test_grabbag.valgrind.log
+	else
+		test_cuesheet${EXE} $*
+	fi
+}
+
+run_test_picture ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 test_picture $*" >>test_grabbag.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 test_picture${EXE} $* 4>>test_grabbag.valgrind.log
+	else
+		test_picture${EXE} $*
+	fi
+}
+
+########################################################################
+#
+# test_picture
+#
+########################################################################
+
+log=picture.log
+picture_dir=${top_srcdir}/test/pictures
+
+echo "Running test_picture..."
+
+rm -f $log
+
+run_test_picture $picture_dir >> $log 2>&1
+
+if [ $is_win = yes ] ; then
+	diff -w ${top_srcdir}/test/picture.ok $log > picture.diff || die "Error: .log file does not match .ok file, see picture.diff"
+else
+	diff ${top_srcdir}/test/picture.ok $log > picture.diff || die "Error: .log file does not match .ok file, see picture.diff"
+fi
+
+echo "PASSED (results are in $log)"
+
+########################################################################
+#
+# test_cuesheet
+#
+########################################################################
+
+log=cuesheet.log
+bad_cuesheets=${top_srcdir}/test/cuesheets/bad.*.cue
+good_cuesheets=${top_srcdir}/test/cuesheets/good.*.cue
+good_leadout=`expr 80 \* 60 \* 44100`
+bad_leadout=`expr $good_leadout + 1`
+
+echo "Running test_cuesheet..."
+
+rm -f $log
+
+#
+# negative tests
+#
+for cuesheet in $bad_cuesheets ; do
+	echo "NEGATIVE $cuesheet" | sed "s|${top_srcdir}/test/||" >> $log 2>&1
+	run_test_cuesheet $cuesheet $good_leadout 44100 cdda >> $log 2>&1 || exit_code=$?
+	if [ "$exit_code" = 255 ] ; then
+		die "Error: test script is broken"
+	fi
+	cuesheet_pass1=${cuesheet}.1
+	cuesheet_pass2=${cuesheet}.2
+	rm -f $cuesheet_pass1 $cuesheet_pass2
+done
+
+#
+# positive tests
+#
+for cuesheet in $good_cuesheets ; do
+	echo "POSITIVE $cuesheet" | sed "s|${top_srcdir}/test/||" >> $log 2>&1
+	run_test_cuesheet $cuesheet $good_leadout 44100 cdda >> $log 2>&1
+	exit_code=$?
+	if [ "$exit_code" = 255 ] ; then
+		die "Error: test script is broken"
+	elif [ "$exit_code" != 0 ] ; then
+		die "Error: good cuesheet is broken"
+	fi
+	cuesheet_out=$(echo $cuesheet | sed "s|${top_srcdir}/test/||")
+	cuesheet_pass1=${cuesheet_out}.1
+	cuesheet_pass2=${cuesheet_out}.2
+	diff $cuesheet_pass1 $cuesheet_pass2 >> $log 2>&1 || die "Error: pass1 and pass2 output differ"
+	rm -f $cuesheet_pass1 $cuesheet_pass2
+done
+
+if [ $is_win = yes ] ; then
+	diff -w ${top_srcdir}/test/cuesheet.ok $log > cuesheet.diff || die "Error: .log file does not match .ok file, see cuesheet.diff"
+else
+	diff ${top_srcdir}/test/cuesheet.ok $log > cuesheet.diff || die "Error: .log file does not match .ok file, see cuesheet.diff"
+fi
+
+echo "PASSED (results are in $log)"
diff --git a/test/test_libFLAC++.sh b/test/test_libFLAC++.sh
new file mode 100755
index 0000000..d71f36f
--- /dev/null
+++ b/test/test_libFLAC++.sh
@@ -0,0 +1,35 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+PATH=../src/test_libFLAC++:$PATH
+PATH=../objs/$BUILD/bin:$PATH
+
+run_test_libFLACpp ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 test_libFLAC++${EXE} $* 4>>test_libFLAC++.valgrind.log
+	else
+		test_libFLAC++${EXE} $*
+	fi
+}
+
+run_test_libFLACpp || die "ERROR during test_libFLAC++"
diff --git a/test/test_libFLAC.sh b/test/test_libFLAC.sh
new file mode 100755
index 0000000..2259eb0
--- /dev/null
+++ b/test/test_libFLAC.sh
@@ -0,0 +1,35 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+PATH=../src/test_libFLAC:$PATH
+PATH=../objs/$BUILD/bin:$PATH
+
+run_test_libFLAC ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 test_libFLAC${EXE} $* 4>>test_libFLAC.valgrind.log
+	else
+		test_libFLAC${EXE} $*
+	fi
+}
+
+run_test_libFLAC || die "ERROR during test_libFLAC"
diff --git a/test/test_metaflac.sh b/test/test_metaflac.sh
new file mode 100755
index 0000000..3df56a4
--- /dev/null
+++ b/test/test_metaflac.sh
@@ -0,0 +1,377 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+PATH=`pwd`/../src/flac:$PATH
+PATH=`pwd`/../src/metaflac:$PATH
+PATH=`pwd`/../objs/$BUILD/bin:$PATH
+
+if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+	then EGREP='grep -E'
+	else EGREP='egrep'
+fi
+
+testdir="metaflac-test-files"
+flacfile="metaflac.flac"
+
+flac${EXE} --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+metaflac${EXE} --help 1>/dev/null 2>/dev/null || die "ERROR can't find metaflac executable"
+
+run_flac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 flac $*" >>test_metaflac.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 flac${EXE} ${TOTALLY_SILENT} --no-error-on-compression-fail $* 4>>test_metaflac.valgrind.log
+	else
+		flac${EXE} ${TOTALLY_SILENT} --no-error-on-compression-fail $*
+	fi
+}
+
+run_metaflac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 metaflac $*" >>test_metaflac.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 metaflac${EXE} $* 4>>test_metaflac.valgrind.log
+	else
+		metaflac${EXE} $*
+	fi
+}
+
+run_metaflac_silent ()
+{
+	if [ -z "$SILENT" ] ; then
+		run_metaflac $*
+	else
+		if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+			echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 metaflac $*" >>test_metaflac.valgrind.log
+			valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 metaflac${EXE} $* 2>/dev/null 4>>test_metaflac.valgrind.log
+		else
+			metaflac${EXE} $* 2>/dev/null
+		fi
+	fi
+}
+
+check_flac ()
+{
+	run_flac --silent --test $flacfile || die "ERROR in $flacfile" 1>&2
+}
+
+echo "Generating stream..."
+bytes=80000
+if dd if=/dev/zero ibs=1 count=$bytes 2>/dev/null | flac${EXE} ${TOTALLY_SILENT} --force --verify -0 --input-size=$bytes --output-name=$flacfile --force-raw-format --endian=big --sign=signed --channels=1 --bps=8 --sample-rate=8000 - ; then
+	chmod +w $flacfile
+else
+	die "ERROR during generation"
+fi
+
+check_flac
+
+testdatadir=${top_srcdir}/test/metaflac-test-files
+
+filter ()
+{
+	# minor danger, changing vendor strings will change the length of the
+	# VORBIS_COMMENT block, but if we add "^  length: " to the patterns,
+	# we lose info about PADDING size that we need
+	# grep pattern 1: remove vendor string
+	# grep pattern 2: remove minimum/maximum frame and block size from STREAMINFO
+	# grep pattern 3: remove hexdump data from PICTURE metadata blocks
+	# sed pattern 1: remove stream offset values from SEEKTABLE points
+	$EGREP -v '^  vendor string: |^  m..imum .....size: |^    0000[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]: ' \
+		| sed -e 's/, stream_offset.*//'
+}
+metaflac_test ()
+{
+	case="$testdatadir/$1"
+	desc="$2"
+	args="$3"
+	expect="$case-expect.meta"
+	echo $ECHO_N "test $1: $desc... " $ECHO_C
+	run_metaflac $args $flacfile | filter > $testdir/out1.meta || die "ERROR running metaflac"
+	# Ignore lengths which can be affected by the version string.
+	sed "s/length:.*/length: XXX/" $testdir/out1.meta > $testdir/out.meta
+	diff -w $expect $testdir/out.meta > /dev/null 2>&1 || die "ERROR: metadata does not match expected $expect"
+	# To blindly accept (and check later): cp -f $testdir/out.meta $expect
+	echo OK
+}
+
+metaflac_test case00 "--list" "--list"
+
+metaflac_test case01 "STREAMINFO --show-* shortcuts" "
+	--show-md5sum
+	--show-min-blocksize
+	--show-max-blocksize
+	--show-min-framesize
+	--show-max-framesize
+	--show-sample-rate
+	--show-channels
+	--show-bps
+	--show-total-samples"
+
+run_metaflac --preserve-modtime --add-padding=12345 $flacfile
+check_flac
+metaflac_test case02 "--add-padding" "--list"
+
+# some flavors of /bin/sh (e.g. Darwin's) won't even handle quoted spaces, so we underscore:
+run_metaflac --set-tag="ARTIST=The_artist_formerly_known_as_the_artist..." $flacfile
+check_flac
+metaflac_test case03 "--set-tag=ARTIST" "--list"
+
+run_metaflac --set-tag="ARTIST=Chuck_Woolery" $flacfile
+check_flac
+metaflac_test case04 "--set-tag=ARTIST" "--list"
+
+run_metaflac --set-tag="ARTIST=Vern" $flacfile
+check_flac
+metaflac_test case05 "--set-tag=ARTIST" "--list"
+
+run_metaflac --set-tag="TITLE=He_who_smelt_it_dealt_it" $flacfile
+check_flac
+metaflac_test case06 "--set-tag=TITLE" "--list"
+
+metaflac_test case07 "--show-vendor-tag --show-tag=ARTIST" "--show-vendor-tag --show-tag=ARTIST"
+
+run_metaflac --remove-first-tag=ARTIST $flacfile
+check_flac
+metaflac_test case08 "--remove-first-tag=ARTIST" "--list"
+
+run_metaflac --remove-tag=ARTIST $flacfile
+check_flac
+metaflac_test case09 "--remove-tag=ARTIST" "--list"
+
+metaflac_test case10 "--list --block-type=VORBIS_COMMENT" "--list --block-type=VORBIS_COMMENT"
+metaflac_test case11 "--list --block-number=0" "--list --block-number=0"
+metaflac_test case12 "--list --block-number=1,2,999" "--list --block-number=1,2,999"
+metaflac_test case13 "--list --block-type=VORBIS_COMMENT,PADDING" "--list --block-type=VORBIS_COMMENT,PADDING"
+metaflac_test case14 "--list --except-block-type=SEEKTABLE,VORBIS_COMMENT" "--list --except-block-type=SEEKTABLE,VORBIS_COMMENT"
+metaflac_test case15 "--list --except-block-type=STREAMINFO" "--list --except-block-type=STREAMINFO"
+
+run_metaflac --add-padding=4321 $flacfile $flacfile
+check_flac
+metaflac_test case16 "--add-padding=4321 * 2" "--list"
+
+run_metaflac --merge-padding $flacfile
+check_flac
+metaflac_test case17 "--merge-padding" "--list"
+
+run_metaflac --add-padding=0 $flacfile
+check_flac
+metaflac_test case18 "--add-padding=0" "--list"
+
+run_metaflac --sort-padding $flacfile
+check_flac
+metaflac_test case19 "--sort-padding" "--list"
+
+run_metaflac --add-padding=0 $flacfile
+check_flac
+metaflac_test case20 "--add-padding=0" "--list"
+
+run_metaflac --remove-all-tags $flacfile
+check_flac
+metaflac_test case21 "--remove-all-tags" "--list"
+
+run_metaflac --remove --block-number=1,99 --dont-use-padding $flacfile
+check_flac
+metaflac_test case22 "--remove --block-number=1,99 --dont-use-padding" "--list"
+
+run_metaflac --remove --block-number=99 --dont-use-padding $flacfile
+check_flac
+metaflac_test case23 "--remove --block-number=99 --dont-use-padding" "--list"
+
+run_metaflac --remove --block-type=PADDING $flacfile
+check_flac
+metaflac_test case24 "--remove --block-type=PADDING" "--list"
+
+run_metaflac --remove --block-type=PADDING --dont-use-padding $flacfile
+check_flac
+metaflac_test case25 "--remove --block-type=PADDING --dont-use-padding" "--list"
+
+run_metaflac --add-padding=0 $flacfile $flacfile
+check_flac
+metaflac_test case26 "--add-padding=0 * 2" "--list"
+
+run_metaflac --remove --except-block-type=PADDING $flacfile
+check_flac
+metaflac_test case27 "--remove --except-block-type=PADDING" "--list"
+
+run_metaflac --remove-all $flacfile
+check_flac
+metaflac_test case28 "--remove-all" "--list"
+
+run_metaflac --remove-all --dont-use-padding $flacfile
+check_flac
+metaflac_test case29 "--remove-all --dont-use-padding" "--list"
+
+run_metaflac --remove-all --dont-use-padding $flacfile
+check_flac
+metaflac_test case30 "--remove-all --dont-use-padding" "--list"
+
+run_metaflac --set-tag="f=0123456789abcdefghij" $flacfile
+check_flac
+metaflac_test case31 "--set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789abcdefghi" $flacfile
+check_flac
+metaflac_test case32 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789abcde" $flacfile
+check_flac
+metaflac_test case33 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0" $flacfile
+check_flac
+metaflac_test case34 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789" $flacfile
+check_flac
+metaflac_test case35 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789abcdefghi" $flacfile
+check_flac
+metaflac_test case36 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789" $flacfile
+check_flac
+metaflac_test case37 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789abcdefghij" $flacfile
+check_flac
+metaflac_test case38 "--remove-all-tags --set-tag=..." "--list"
+
+echo "TITLE=Tittle" | run_metaflac --import-tags-from=- $flacfile
+check_flac
+metaflac_test case39 "--import-tags-from=-" "--list"
+
+cat > vc.txt << EOF
+artist=Fartist
+artist=artits
+EOF
+run_metaflac --import-tags-from=vc.txt $flacfile
+check_flac
+metaflac_test case40 "--import-tags-from=[FILE]" "--list"
+
+rm vc.txt
+
+run_metaflac --add-replay-gain $flacfile
+check_flac
+metaflac_test case41 "--add-replay-gain" "--list"
+
+run_metaflac --remove-replay-gain $flacfile
+check_flac
+metaflac_test case42 "--remove-replay-gain" "--list"
+
+run_metaflac --scan-replay-gain $flacfile
+check_flac
+metaflac_test case42 "--scan-replay-gain" "--list"
+
+# CUESHEET blocks
+cs_in=${top_srcdir}/test/cuesheets/good.000.cue
+cs_out=metaflac.cue
+cs_out2=metaflac2.cue
+run_metaflac --import-cuesheet-from="$cs_in" $flacfile
+check_flac
+metaflac_test case43 "--import-cuesheet-from" "--list"
+run_metaflac --export-cuesheet-to=$cs_out $flacfile
+run_metaflac --remove --block-type=CUESHEET $flacfile
+check_flac
+metaflac_test case44 "--remove --block-type=CUESHEET" "--list"
+run_metaflac --import-cuesheet-from=$cs_out $flacfile
+check_flac
+metaflac_test case45 "--import-cuesheet-from" "--list"
+run_metaflac --export-cuesheet-to=$cs_out2 $flacfile
+echo "comparing cuesheets:"
+diff $cs_out $cs_out2 || die "ERROR, cuesheets should be identical"
+echo identical
+
+rm -f $cs_out $cs_out2
+
+# PICTURE blocks
+ncase=46
+for f in \
+	0.gif \
+	1.gif \
+	2.gif \
+; do
+	run_metaflac --import-picture-from="|image/gif|$f||${top_srcdir}/test/pictures/$f" $flacfile
+	check_flac
+	metaflac_test "case$ncase" "--import-picture-from" "--list"
+	ncase=`expr $ncase + 1`
+done
+for f in \
+	0.jpg \
+	4.jpg \
+; do
+	run_metaflac --import-picture-from="4|image/jpeg|$f||${top_srcdir}/test/pictures/$f" $flacfile
+	check_flac
+	metaflac_test "case$ncase" "--import-picture-from" "--list"
+	ncase=`expr $ncase + 1`
+done
+for f in \
+	0.png \
+	1.png \
+	2.png \
+	3.png \
+	4.png \
+	5.png \
+	6.png \
+	7.png \
+	8.png \
+; do
+	run_metaflac --import-picture-from="5|image/png|$f||${top_srcdir}/test/pictures/$f" $flacfile
+	check_flac
+	metaflac_test "case$ncase" "--import-picture-from" "--list"
+	ncase=`expr $ncase + 1`
+done
+[ $ncase = 60 ] || die "expected case# to be 60"
+
+fn=export-picture-check
+echo $ECHO_N "Testing --export-picture-to... " $ECHO_C
+run_metaflac --export-picture-to=$fn $flacfile
+check_flac
+cmp $fn ${top_srcdir}/test/pictures/0.gif || die "ERROR, exported picture file and original differ"
+echo OK
+rm -f $fn
+echo $ECHO_N "Testing --block-number --export-picture-to... " $ECHO_C
+run_metaflac --block-number=9 --export-picture-to=$fn $flacfile
+check_flac
+cmp $fn ${top_srcdir}/test/pictures/0.png || die "ERROR, exported picture file and original differ"
+echo OK
+rm -f $fn
+
+run_metaflac --remove --block-type=PICTURE $flacfile
+check_flac
+metaflac_test case60 "--remove --block-type=PICTURE" "--list"
+run_metaflac --import-picture-from="1|image/png|standard_icon|32x32x24|${top_srcdir}/test/pictures/0.png" $flacfile
+check_flac
+metaflac_test case61 "--import-picture-from" "--list"
+run_metaflac --import-picture-from="2|image/png|icon|64x64x24|${top_srcdir}/test/pictures/1.png" $flacfile
+check_flac
+metaflac_test case62 "--import-picture-from" "--list"
+
+# UNKNOWN blocks
+echo $ECHO_N "Testing FLAC file with unknown metadata... " $ECHO_C
+cp -p ${top_srcdir}/test/metaflac.flac.in $flacfile
+# remove the VORBIS_COMMENT block so vendor string changes don't interfere with the comparison:
+run_metaflac --remove --block-type=VORBIS_COMMENT --dont-use-padding $flacfile
+cmp $flacfile ${top_srcdir}/test/metaflac.flac.ok || die "ERROR, $flacfile and metaflac.flac.ok differ"
+echo OK
+
+rm -f metaflac-test-files/out.meta  metaflac-test-files/out1.meta
diff --git a/test/test_replaygain.sh b/test/test_replaygain.sh
new file mode 100755
index 0000000..2e7ab53
--- /dev/null
+++ b/test/test_replaygain.sh
@@ -0,0 +1,146 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+PATH=`pwd`/../src/flac:$PATH
+PATH=`pwd`/../src/metaflac:$PATH
+PATH=`pwd`/../objs/$BUILD/bin:$PATH
+
+if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+	then EGREP='grep -E'
+	else EGREP='egrep'
+fi
+
+testdir="metaflac-test-files"
+flacfile="replaygain.flac"
+
+run_flac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 flac $*" >>test_replaygain.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 flac --no-error-on-compression-fail $* 4>>test_replaygain.valgrind.log
+	else
+		flac${EXE} --no-error-on-compression-fail $*
+	fi
+}
+
+run_metaflac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 metaflac $*" >>test_replaygain.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 metaflac $* 4>>test_replaygain.valgrind.log
+	else
+		metaflac${EXE} $*
+	fi
+}
+
+run_metaflac_silent ()
+{
+	if [ -z "$SILENT" ] ; then
+		run_metaflac $*
+	else
+		if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+			echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 metaflac $*" >>test_replaygain.valgrind.log
+			valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 metaflac $* 2>/dev/null 4>>test_replaygain.valgrind.log
+		else
+			metaflac${EXE} $* 2>/dev/null
+		fi
+	fi
+}
+
+check_flac ()
+{
+	run_flac --silent --test $flacfile || die "ERROR in $flacfile" 1>&2
+}
+
+echo "Generating stream..."
+bytes=80000
+if dd if=/dev/zero ibs=1 count=$bytes 2>/dev/null | flac${EXE} --silent --force --verify -0 --input-size=$bytes --output-name=$flacfile --force-raw-format --endian=big --sign=signed --channels=1 --bps=8 --sample-rate=8000 - ; then
+	chmod +w $flacfile
+else
+	die "ERROR during generation"
+fi
+
+check_flac
+
+# Replay gain tests - Test the rates which have specific filter table entries
+# and verify that harmonics can be processed correctly.
+
+tonegenerator ()
+{
+    flac${EXE} --force --output-name=$2 --silent --no-seektable --no-error-on-compression-fail rpg-tone-$1.wav
+}
+
+REPLAYGAIN_FREQ=
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ  8000/-12.73"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 11025/-12.91"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 12000/-12.98"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 16000/-13.27"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 18900/-13.41"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 22050/-13.77"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 24000/-13.82"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 28000/-14.06"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 32000/-14.08"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 36000/-14.12"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 37800/-14.18"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 44100/-14.17"
+REPLAYGAIN_FREQ="$REPLAYGAIN_FREQ 48000/-14.16:1:2:4"
+
+set -e
+
+for ACTION in $REPLAYGAIN_FREQ ; do
+  if [ -n "${ACTION##*:*}" ] ; then
+    HARMONICS=1
+  else
+    HARMONICS="${ACTION#*:}"
+  fi
+  FREQ="${ACTION%%/*}"
+  GAIN="${ACTION#*/}"
+  GAIN="${GAIN%%:*}"
+  while [ -n "$HARMONICS" ] ; do
+    MULTIPLE="${HARMONICS%%:*}"
+    if [ x"$MULTIPLE" = x"$HARMONICS" ] ; then
+      HARMONICS=
+    else
+      HARMONICS="${HARMONICS#*:}"
+    fi
+    RATE=$(($MULTIPLE * FREQ))
+    [ $MULTIPLE -eq 1 -o -n "${REPLAYGAIN_FREQ##* $RATE/*}" ] || break
+    echo $ECHO_N "Testing FLAC replaygain $RATE ($FREQ x $MULTIPLE) ... " $ECHO_C
+    tonegenerator $RATE $flacfile
+    run_metaflac --scan-replay-gain $flacfile
+    run_metaflac --add-replay-gain $flacfile
+    run_metaflac --list $flacfile | grep REPLAYGAIN.*GAIN= |
+    while read -r REPLAYGAIN ; do
+      MEASUREDGAIN="${REPLAYGAIN##*=}"
+      MEASUREDGAIN="${MEASUREDGAIN%% *}"
+      if [ x"$MEASUREDGAIN" != x"$GAIN" ] ; then
+        die "ERROR, Expected $GAIN db instead of $REPLAYGAIN"
+      fi
+    done
+    echo OK
+  done
+done
+
+
+rm -f $testdir/out.flac $testdir/out.meta
+
+exit 0
diff --git a/test/test_seeking.sh b/test/test_seeking.sh
new file mode 100755
index 0000000..316d3db
--- /dev/null
+++ b/test/test_seeking.sh
@@ -0,0 +1,141 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2004-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+PATH=../src/flac:$PATH
+PATH=../src/metaflac:$PATH
+PATH=../src/test_seeking:$PATH
+PATH=../src/test_streams:$PATH
+PATH=../objs/$BUILD/bin:$PATH
+
+if [ x"$FLAC__TEST_LEVEL" = x ] ; then
+	FLAC__TEST_LEVEL=1
+fi
+
+flac${EXE} --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+metaflac${EXE} --help 1>/dev/null 2>/dev/null || die "ERROR can't find metaflac executable"
+
+run_flac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 flac $*" >>test_seeking.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 flac${EXE} --no-error-on-compression-fail $* 4>>test_seeking.valgrind.log
+	else
+		flac${EXE} --no-error-on-compression-fail $*
+	fi
+}
+
+run_metaflac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 metaflac $*" >>test_seeking.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 metaflac${EXE} $* 4>>test_seeking.valgrind.log
+	else
+		metaflac${EXE} $*
+	fi
+}
+
+run_test_seeking ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 test_seeking $*" >>test_seeking.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 test_seeking $* 4>>test_seeking.valgrind.log
+	else
+		test_seeking${EXE} $*
+	fi
+}
+
+echo $ECHO_N "Checking for --ogg support in flac ... " $ECHO_C
+if flac${EXE} --ogg --no-error-on-compression-fail --silent --force-raw-format --endian=little --sign=signed --channels=1 --bps=8 --sample-rate=44100 -c $0 1>/dev/null 2>&1 ; then
+	has_ogg=yes;
+else
+	has_ogg=no;
+fi
+echo ${has_ogg}
+
+echo "Generating streams..."
+if [ ! -f noise.raw ] ; then
+	test_streams || die "ERROR during test_streams"
+fi
+
+echo "generating FLAC files for seeking:"
+run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=8 --channels=1 --blocksize=576 -S- --output-name=tiny.flac noise8m32.raw || die "ERROR generating FLAC file"
+run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=576 -S- --output-name=small.flac noise.raw || die "ERROR generating FLAC file"
+run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=8 --channels=1 --blocksize=576 -S10x --output-name=tiny-s.flac noise8m32.raw || die "ERROR generating FLAC file"
+run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=576 -S10x --output-name=small-s.flac noise.raw || die "ERROR generating FLAC file"
+
+tiny_samples=`metaflac${EXE} --show-total-samples tiny.flac`
+small_samples=`metaflac${EXE} --show-total-samples small.flac`
+
+tiny_seek_count=100
+if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+	small_seek_count=10000
+else
+	small_seek_count=100
+fi
+
+for suffix in '' '-s' ; do
+	echo "testing tiny$suffix.flac:"
+	if run_test_seeking tiny$suffix.flac $tiny_seek_count $tiny_samples noise8m32.raw ; then : ; else
+		die "ERROR: during test_seeking"
+	fi
+
+	echo "testing small$suffix.flac:"
+	if run_test_seeking small$suffix.flac $small_seek_count $small_samples noise.raw ; then : ; else
+		die "ERROR: during test_seeking"
+	fi
+
+	echo "removing sample count from tiny$suffix.flac and small$suffix.flac:"
+	if run_metaflac --no-filename --set-total-samples=0 tiny$suffix.flac small$suffix.flac ; then : ; else
+		die "ERROR: during metaflac"
+	fi
+
+	echo "testing tiny$suffix.flac with total_samples=0:"
+	if run_test_seeking tiny$suffix.flac $tiny_seek_count $tiny_samples noise8m32.raw ; then : ; else
+		die "ERROR: during test_seeking"
+	fi
+
+	echo "testing small$suffix.flac with total_samples=0:"
+	if run_test_seeking small$suffix.flac $small_seek_count $small_samples noise.raw ; then : ; else
+		die "ERROR: during test_seeking"
+	fi
+done
+
+if [ $has_ogg = "yes" ] ; then
+
+	echo "generating Ogg FLAC files for seeking:"
+	run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=8 --channels=1 --blocksize=576 --output-name=tiny.oga --ogg noise8m32.raw || die "ERROR generating Ogg FLAC file"
+	run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=576 --output-name=small.oga --ogg noise.raw || die "ERROR generating Ogg FLAC file"
+	# seek tables are not used in Ogg FLAC
+
+	echo "testing tiny.oga:"
+	if run_test_seeking tiny.oga $tiny_seek_count $tiny_samples noise8m32.raw ; then : ; else
+		die "ERROR: during test_seeking"
+	fi
+
+	echo "testing small.oga:"
+	if run_test_seeking small.oga $small_seek_count $small_samples noise.raw ; then : ; else
+		die "ERROR: during test_seeking"
+	fi
+
+fi
+
+rm -f tiny.flac tiny.oga small.flac small.oga tiny-s.flac small-s.flac
diff --git a/test/test_streams.sh b/test/test_streams.sh
new file mode 100755
index 0000000..f4cbd00
--- /dev/null
+++ b/test/test_streams.sh
@@ -0,0 +1,257 @@
+#!/bin/sh -e
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001-2009  Josh Coalson
+#  Copyright (C) 2011-2016  Xiph.Org Foundation
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under different licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+. ./common.sh
+
+PATH=../src/flac:$PATH
+PATH=../src/test_streams:$PATH
+PATH=../objs/$BUILD/bin:$PATH
+
+if [ x"$FLAC__TEST_LEVEL" = x ] ; then
+	FLAC__TEST_LEVEL=1
+fi
+
+flac${EXE} --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+
+run_flac ()
+{
+	if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+		echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=50 flac $*" >>test_streams.valgrind.log
+		valgrind --leak-check=yes --show-reachable=yes --num-callers=50 --log-fd=4 flac --no-error-on-compression-fail $* 4>>test_streams.valgrind.log
+	else
+		flac${EXE} --no-error-on-compression-fail $*
+	fi
+}
+
+echo "Generating streams..."
+if [ ! -f wacky1.wav ] ; then
+	test_streams || die "ERROR: missing files"
+fi
+
+#
+# single-file test routines
+#
+
+test_file ()
+{
+	name=$1
+	channels=$2
+	bps=$3
+	encode_options="$4"
+
+	echo $ECHO_N "$name (--channels=$channels --bps=$bps $encode_options): encode..." $ECHO_C
+	cmd="run_flac --verify --silent --force --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels $encode_options --no-padding $name.raw"
+	echo "### ENCODE $name #######################################################" >> ./streams.log
+	echo "###    cmd=$cmd" >> ./streams.log
+	$cmd 2>>./streams.log || die "ERROR during encode of $name"
+
+	echo $ECHO_N "decode..." $ECHO_C
+	cmd="run_flac --silent --force --endian=little --sign=signed --decode --force-raw-format --output-name=$name.cmp $name.flac"
+	echo "### DECODE $name #######################################################" >> ./streams.log
+	echo "###    cmd=$cmd" >> ./streams.log
+	$cmd 2>>./streams.log || die "ERROR during decode of $name"
+
+	ls -1l $name.raw >> ./streams.log
+	ls -1l $name.flac >> ./streams.log
+	ls -1l $name.cmp >> ./streams.log
+
+	echo $ECHO_N "compare..." $ECHO_C
+	cmp $name.raw $name.cmp || die "ERROR during compare of $name"
+
+	echo OK
+}
+
+test_file_piped ()
+{
+	name=$1
+	channels=$2
+	bps=$3
+	encode_options="$4"
+
+	if [ `env | grep -ic '^comspec='` != 0 ] ; then
+		is_win=yes
+	else
+		is_win=no
+	fi
+
+	echo $ECHO_N "$name: encode via pipes..." $ECHO_C
+	if [ $is_win = yes ] ; then
+		cmd="run_flac --verify --silent --force --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels $encode_options --no-padding --stdout $name.raw"
+		echo "### ENCODE $name #######################################################" >> ./streams.log
+		echo "###    cmd=$cmd" >> ./streams.log
+		$cmd 1>$name.flac 2>>./streams.log || die "ERROR during encode of $name"
+	else
+		cmd="run_flac --verify --silent --force --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels $encode_options --no-padding --stdout -"
+		echo "### ENCODE $name #######################################################" >> ./streams.log
+		echo "###    cmd=$cmd" >> ./streams.log
+		cat $name.raw | $cmd 1>$name.flac 2>>./streams.log || die "ERROR during encode of $name"
+	fi
+	echo $ECHO_N "decode via pipes..." $ECHO_C
+	if [ $is_win = yes ] ; then
+		cmd="run_flac --silent --force --endian=little --sign=signed --decode --force-raw-format --stdout $name.flac"
+		echo "### DECODE $name #######################################################" >> ./streams.log
+		echo "###    cmd=$cmd" >> ./streams.log
+		$cmd 1>$name.cmp 2>>./streams.log || die "ERROR during decode of $name"
+	else
+		cmd="run_flac --silent --force --endian=little --sign=signed --decode --force-raw-format --stdout -"
+		echo "### DECODE $name #######################################################" >> ./streams.log
+		echo "###    cmd=$cmd" >> ./streams.log
+		cat $name.flac | $cmd 1>$name.cmp 2>>./streams.log || die "ERROR during decode of $name"
+	fi
+	ls -1l $name.raw >> ./streams.log
+	ls -1l $name.flac >> ./streams.log
+	ls -1l $name.cmp >> ./streams.log
+
+	echo $ECHO_N "compare..." $ECHO_C
+	cmp $name.raw $name.cmp || die "ERROR during compare of $name"
+
+	echo OK
+}
+
+if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+	max_lpc_order=32
+else
+	max_lpc_order=16
+fi
+
+echo "Testing noise through pipes..."
+test_file_piped noise 1 8 "-0"
+
+echo "Testing small files..."
+test_file test01 1 16 "-0 -l $max_lpc_order --lax -m -e -p"
+test_file test02 2 16 "-0 -l $max_lpc_order --lax -m -e -p"
+test_file test03 1 16 "-0 -l $max_lpc_order --lax -m -e -p"
+test_file test04 2 16 "-0 -l $max_lpc_order --lax -m -e -p"
+
+for bps in 8 16 24 ; do
+	echo "Testing $bps-bit full-scale deflection streams..."
+	for b in 01 02 03 04 05 06 07 ; do
+		test_file fsd$bps-$b 1 $bps "-0 -l $max_lpc_order --lax -m -e -p"
+	done
+done
+
+echo "Testing 16-bit wasted-bits-per-sample streams..."
+for b in 01 ; do
+	test_file wbps16-$b 1 16 "-0 -l $max_lpc_order --lax -m -e -p"
+done
+
+for bps in 8 16 24 ; do
+	echo "Testing $bps-bit sine wave streams..."
+	for b in 00 ; do
+		test_file sine${bps}-$b 1 $bps "-0 -l $max_lpc_order --lax -m -e --sample-rate=48000"
+	done
+	for b in 01 ; do
+		test_file sine${bps}-$b 1 $bps "-0 -l $max_lpc_order --lax -m -e --sample-rate=96000"
+	done
+	for b in 02 03 04 ; do
+		test_file sine${bps}-$b 1 $bps "-0 -l $max_lpc_order --lax -m -e"
+	done
+	for b in 10 11 ; do
+		test_file sine${bps}-$b 2 $bps "-0 -l $max_lpc_order --lax -m -e --sample-rate=48000"
+	done
+	for b in 12 ; do
+		test_file sine${bps}-$b 2 $bps "-0 -l $max_lpc_order --lax -m -e --sample-rate=96000"
+	done
+	for b in 13 14 15 16 17 18 19 ; do
+		test_file sine${bps}-$b 2 $bps "-0 -l $max_lpc_order --lax -m -e"
+	done
+done
+
+echo "Testing blocksize variations..."
+for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+	for blocksize in 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ; do
+		for lpc_order in 0 1 2 3 4 5 7 8 9 15 16 17 31 32 ; do
+			if [ $lpc_order = 0 ] || [ $lpc_order -le $blocksize ] ; then
+				test_file noise8m32 1 8 "-8 -p -e -l $lpc_order --lax --blocksize=$blocksize $disable"
+			fi
+		done
+	done
+done
+
+echo "Testing some frame header variations..."
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax -b $max_lpc_order"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax -b 65535"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=9"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=90"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=90000"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=9"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=90"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=90000"
+
+echo "Testing option variations..."
+for f in 00 01 02 03 04 ; do
+	for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+		if [ -z "$disable" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+			for opt in 0 1 2 4 5 6 8 ; do
+				for extras in '' '-p' '-e' ; do
+					if [ -z "$extras" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+						test_file sine16-$f 1 16 "-$opt $extras $disable"
+					fi
+				done
+			done
+			if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+				test_file sine16-$f 1 16 "-b 16384 -m -r 8 -l $max_lpc_order --lax -e -p $disable"
+			fi
+		fi
+	done
+done
+
+for f in 10 11 12 13 14 15 16 17 18 19 ; do
+	for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+		if [ -z "$disable" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+			for opt in 0 1 2 4 5 6 8 ; do
+				for extras in '' '-p' '-e' ; do
+					if [ -z "$extras" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+						test_file sine16-$f 2 16 "-$opt $extras $disable"
+					fi
+				done
+			done
+			if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+				test_file sine16-$f 2 16 "-b 16384 -m -r 8 -l $max_lpc_order --lax -e -p $disable"
+			fi
+		fi
+	done
+done
+
+echo "Testing noise..."
+for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+	if [ -z "$disable" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+		for channels in 1 2 4 8 ; do
+			if [ $channels -le 2 ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+				for bps in 8 16 24 ; do
+					for opt in 0 1 2 3 4 5 6 7 8 ; do
+						for extras in '' '-p' '-e' ; do
+							if [ -z "$extras" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+								for blocksize in '' '--lax -b 32' '--lax -b 32768' '--lax -b 65535' ; do
+									if [ -z "$blocksize" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+										test_file noise $channels $bps "-$opt $extras $blocksize $disable"
+									fi
+								done
+							fi
+						done
+					done
+					if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+						test_file noise $channels $bps "-b 16384 -m -r 8 -l $max_lpc_order --lax -e -p $disable"
+					fi
+				done
+			fi
+		done
+	fi
+done
diff --git a/test/write_iff.pl b/test/write_iff.pl
new file mode 100755
index 0000000..f9efa74
--- /dev/null
+++ b/test/write_iff.pl
@@ -0,0 +1,211 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+require Math::BigInt;
+
+my $usage = "
+$0 <format> <bps> <channels> <sample-rate> <#samples> <sample-type>
+
+     <format> is one of aiff,wave,wave64,rf64
+        <bps> is 8,16,24,32
+   <channels> is 1-8
+<sample-rate> is any 32-bit value
+   <#samples> is 0-2^64-1
+<sample-type> is one of zero,rand
+
+";
+
+die $usage unless @ARGV == 6;
+
+my %formats = ( 'aiff'=>1, 'wave'=>1, 'wave64'=>1, 'rf64'=>1 );
+my %sampletypes = ( 'zero'=>1, 'rand'=>1 );
+my @channelmask = ( 0, 1, 3, 7, 0x33, 0x607, 0x60f, 0, 0 ); #@@@@@@ need proper masks for 7,8
+
+my ($format, $bps, $channels, $samplerate, $samples, $sampletype) = @ARGV;
+my $bigsamples = new Math::BigInt $samples;
+
+die $usage unless defined $formats{$format};
+die $usage unless $bps == 8 || $bps == 16 || $bps == 24 || $bps == 32;
+die $usage unless $channels >= 1 && $channels <= 8;
+die $usage unless $samplerate >= 0 && $samplerate <= 4294967295;
+die $usage unless defined $sampletypes{$sampletype};
+
+# convert bits-per-sample to bytes-per-sample
+$bps /= 8;
+
+my $datasize = $samples * $bps * $channels;
+my $bigdatasize = $bigsamples * $bps * $channels;
+
+my $padding = int($bigdatasize & 1); # for aiff/wave/rf64 chunk alignment
+my $padding8 = 8 - int($bigdatasize & 7); $padding8 = 0 if $padding8 == 8; # for wave64 alignment
+# wave-ish file needs to be WAVEFORMATEXTENSIBLE?
+my $wavx = ($format eq 'wave' || $format eq 'wave64' || $format eq 'rf64') && ($channels > 2 || ($bps != 8 && $bps != 16));
+
+# write header
+
+if ($format eq 'aiff') {
+	die "sample data too big for format\n" if 46 + $datasize + $padding > 4294967295;
+	# header
+	print "FORM";
+	print pack('N', 46 + $datasize + $padding);
+	print "AIFF";
+	# COMM chunk
+	print "COMM";
+	print pack('N', 18); # chunk size = 18
+	print pack('n', $channels);
+	print pack('N', $samples);
+	print pack('n', $bps * 8);
+	print pack_sane_extended($samplerate);
+	# SSND header
+	print "SSND";
+	print pack('N', $datasize + 8); # chunk size
+	print pack('N', 0); # ssnd_offset_size
+	print pack('N', 0); # blocksize
+}
+elsif ($format eq 'wave' || $format eq 'wave64' || $format eq 'rf64') {
+	die "sample data too big for format\n" if $format eq 'wave' && ($wavx?60:36) + $datasize + $padding > 4294967295;
+	# header
+	if ($format eq 'wave') {
+		print "RIFF";
+		# +4 for WAVE
+		# +8+{40,16} for fmt chunk
+		# +8 for data chunk header
+		print pack('V', 4 + 8+($wavx?40:16) + 8 + $datasize + $padding);
+		print "WAVE";
+	}
+	elsif ($format eq 'wave64') {
+		# RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000
+		print "\x72\x69\x66\x66\x2E\x91\xCF\x11\xD6\xA5\x28\xDB\x04\xC1\x00\x00";
+		# +(16+8) for RIFF GUID + size
+		# +16 for WAVE GUID
+		# +16+8+{40,16} for fmt chunk
+		# +16+8 for data chunk header
+		my $bigriffsize = $bigdatasize + (16+8) + 16 + 16+8+($wavx?40:16) + (16+8) + $padding8;
+		print pack_64('V', $bigriffsize);
+		# WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A
+		print "\x77\x61\x76\x65\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A";
+	}
+	else {
+		print "RF64";
+		print pack('V', 0xffffffff);
+		print "WAVE";
+		# ds64 chunk
+		print "ds64";
+		print pack('V', 28); # chunk size
+		# +4 for WAVE
+		# +(8+28) for ds64 chunk
+		# +8+{40,16} for fmt chunk
+		# +8 for data chunk header
+		my $bigriffsize = $bigdatasize + 4 + (8+28) + 8+($wavx?40:16) + 8 + $padding;
+		print pack_64('V', $bigriffsize);
+		print pack_64('V', $bigdatasize);
+		print pack_64('V', $bigsamples);
+		print pack('V', 0); # table size
+	}
+	# fmt chunk
+	if ($format ne 'wave64') {
+		print "fmt ";
+		print pack('V', $wavx?40:16); # chunk size
+	}
+	else { # wave64
+		# fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A
+		print "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A";
+		print pack('V', 16+8+($wavx?40:16)); # chunk size (+16+8 for GUID and size fields)
+		print pack('V', 0);                  # ...is 8 bytes for wave64
+	}
+	print pack('v', $wavx?65534:1); # compression code
+	print pack('v', $channels);
+	print pack('V', $samplerate);
+	print pack('V', $samplerate * $channels * $bps);
+	print pack('v', $channels * $bps); # block align = channels*((bps+7)/8)
+	print pack('v', $bps * 8); # bits per sample = ((bps+7)/8)*8
+	if ($wavx) {
+		print pack('v', 22); # cbSize
+		print pack('v', $bps * 8); # validBitsPerSample
+		print pack('V', $channelmask[$channels]);
+		# GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}
+		print "\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71";
+	}
+	# data header
+	if ($format ne 'wave64') {
+		print "data";
+		print pack('V', $format eq 'wave'? $datasize : 0xffffffff);
+	}
+	else { # wave64
+		# data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A
+		print "\x64\x61\x74\x61\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A";
+		print pack_64('V', $bigdatasize+16+8); # +16+8 for GUID and size fields
+	}
+}
+else {
+	die;
+}
+
+# write sample data
+
+if ($sampletype eq 'zero') {
+	my $chunk = 4096;
+	my $buf = pack("x[".($channels*$bps*$chunk)."]");
+	for (my $s = $samples; $s > 0; $s -= $chunk) {
+		if ($s < $chunk) {
+			print substr($buf, 0, $channels*$bps*$s);
+		}
+		else {
+			print $buf;
+		}
+	}
+}
+elsif ($sampletype eq 'rand') {
+	for (my $s = 0; $s < $samples; $s++) {
+		for (my $c = 0; $c < $channels; $c++) {
+			for (my $b = 0; $b < $bps; $b++) {
+				print pack('C', int(rand(256)));
+			}
+		}
+	}
+}
+else {
+	die;
+}
+
+# write padding
+if ($format eq 'wave64') {
+	print pack("x[$padding8]") if $padding8;
+}
+else {
+	print "\x00" if $padding;
+}
+
+exit 0;
+
+sub pack_sane_extended
+{
+	my $val = shift;
+	die unless $val > 0;
+	my $shift;
+	for ($shift = 0; ($val>>(31-$shift)) == 0; ++$shift) {
+	}
+	$val <<= $shift;
+	my $exponent = 63 - ($shift + 32);
+	return pack('nNN', $exponent + 16383, $val, 0);
+}
+
+sub pack_64
+{
+	my $c = shift; # 'N' for big-endian, 'V' for little-endian, ala pack()
+	my $v1 = shift; # value, must be Math::BigInt
+	my $v2 = $v1->copy();
+	if ($c eq 'V') {
+		$v1->band(0xffffffff);
+		$v2->brsft(32);
+	}
+	elsif ($c eq 'N') {
+		$v2->band(0xffffffff);
+		$v1->brsft(32);
+	}
+	else {
+		die;
+	}
+	return pack("$c$c", 0+$v1->bstr(), 0+$v2->bstr());
+}